인프런 워밍업 클럽 BE - 3일차 과제
진도표 3일차와 연결됩니다
우리는 JdbcTemplate을 사용하는 과정에서 익명 클래스와 람다식이라는 자바 문법을 사용했습니다. 익명 클래스는 자바의 초창기부터 있던 기능이고, 람다식은 자바 8에서 등장한 기능입니다. 다음 키워드를 사용해 몇 가지 블로그 글을 찾아보세요! 아래 질문을 생각하며 공부해보면 좋습니다! 😊
[키워드]
익명 클래스 / 람다 / 함수형 프로그래밍 / @FunctionalInterface / 스트림 API / 메소드 레퍼런스
[질문]
자바의 람다식은 왜 등장했을까?
람다식과 익명 클래스는 어떤 관계가 있을까? - 람다식의 문법은 어떻게 될까?
익명 클래스(Anonymous Class)
익명클래스는 단어 그대로 이름이 없는 클래스를 말한다.
이름이 없는 클래스이므로 기억되지 않아도 된다는 것이며, 나중에 다시 불러질 이유가 없다는 것이다. 프로그램에서 일시적으로 한 번만 사용되고 버려지는 객체라고 보면 된다. 즉, 일회용 클래스이다.
익명클래스는 클래스 정의와 동시에 객체를 생성할 수 있다. 따로 클래스 정의 없이 메소드 내에서 바로 클래스를 생성해 인스턴스화 할 수 있으며, 이렇게 클래스의 선언과 객체의 생성을 동시에 하기 때문에 단 한번만 사용될 수 있다.
익명클래스는 일회용으로 사용되고 버려지는 클래스이므로, 자식 클래스에서 자주 사용된다. 어떠한 메소드에서 부모 클래스의 자원을 상속받아 재정의하여 사용할 자식 클래스가 한 번만 사용되고 버려질 자료형이라면, 굳이 상단에 클래스를 정의하기보다는 지역 변수처럼 익명클래스로 정의하고 스택이 끝나면 삭제되도록 하는 것이 유지보수면에서도, 메모리면에서도 이점을 얻을 수 있는것이다.
재사용할 필요가 없는 일회성 클래스를 정의하고 생성하는 것은 비효율적이므로, 익명클래스를 사용하여 코드를 줄일 수 있다.
예를 들어, 부모 클래스와 자식 클래스가 다음과 같다고 해보자.
// 부모 클래스
class Animal {
public String bark() {
return "동물이 운다";
}
}
// 자식 클래스
class Dog extends Animal {
@Override
public String bark() {
return "멍멍";
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
dog.bark();
}
}
위의 예시에서, 익명클래스는 클래스 정의와 동시에 객체를 생성할 수 있으므로 아래와 같이 익명클래스를 이용할 수 있다.
// 부모 클래스
class Animal {
public String bark() {
return "동물이 운다";
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Animal() {
@Override
public String bark() {
return "멍멍";
}
}; // 익명클래스에는 끝에 반드시 세미콜론을 붙여줘야 한다.
dog.bark();
}
}
이렇게 익명클래스 방식으로 선언한다면 @Override
어노테이션을 통해 오버라이딩한 메소드만 사용이 가능하며, 새로 정의한 메소드는 익명클래스가 끝나는 순간(;) 사용이 불가능하다.
익명클래스는 클래스필드, 지역변수, 메소드 매개변수로 이용이 가능하다.
보통의 경우, 익명 클래스로 사용하는 일은 드물다. 하지만, 인터페이스를 익명 객체로 선언하여 사용할 때 진가가 발휘된다. 추상화 구조인 인터페이스를 일회용으로 구현하여 사용할 필요가 있을때, 익명클래스를 사용하면 아주 좋다.
// 부모 클래스
interface IAnimal {
public String bark();
public String run(();
}
public class Main {
public static void main(String[] args) {
// 인터페이스 익명 구현객체 생성
IAnimal dog = new IAnimal() {
@Override
public String bark() {
return "멍멍";
}
@Override
public String run() {
return "멍멍달려";
}
}; // 익명클래스에는 끝에 반드시 세미콜론을 붙여줘야 한다.
dog.bark();
dog.run();
}
}
람다 표현식(Lambda Expression)
람다 표현식이란, 함수형 프로그래밍을 구성하기 위한 함수식이며, 간단히 말해 자바의 메소드를 간결한 함수식으로 표현한 것이다.
지금까지 자바에서 메서드 표헌을 위해 클래스를 정의해야 했다면, 람다 표현식이 등장하면서 메서드의 이름과 반환값을 생략하고 이를 변수에 넣어 자바 코드를 매우 간결하게 만들어낼 수 있게 되었다.
add 함수를 기존의 메서드 형식으로 표현한 것과, 람다식으로 표현한 방식을 비교해보자.
// 기존 형식
int add(int a, int b) {
return a + b;
}
// 람다식
(x, y) -> {
return x + y;
}
// 함수에 리턴문 한줄만 있는 경우 중괄호와 return 키워드를 생략할 수 있다.
(x, y) -> x + y
이와 같이, 메서드타입, 이름, 매개변수 타입, 중괄호, return 문을 생략하고 화살표 기호를 넣어 코드를 크게 줄였다. 이러한 표현식을 람다 표현식이라 하며, 이름이 없는 함수. 즉, 익명 함수(anonymous function) 라고도 한다.
람다 표현식은 왜 등장했을까?
위의 내용을 보아, 람다 표현식이 등장한 이유는 불필요한 코드를 줄이고 가독성을 높이기 위함이다. 함수형 인터페이스의 인스턴스를 생성하여 함수를 변수처럼 사용하게 되며, 이러한 경우 메소드의 이름이 불필요하다고 여겨지고 컴파일러가 문맥을 살펴 타입을 추론하게 된다.
림다 표현식은 아래와 같은 장단점이 존재한다.
람다 표현식의 장점
코드를 간결하게 만들 수 있다.
식에 개발자의 의도가 명확히 드러나기 때문에 가독성이 높아진다.
함수를 만드는 과정 없이 한번에 처리할 수 있어 생산성이 높아진다.
병렬프로그래밍이 용이하다.
람다 표현식의 단점
익명함수는 재사용이 불가능하다.
디버깅이 어렵다.
중복코드가 생성되어 코드가 지저분해질 수 있다.
재귀함수로는 부적합하다.
람다표현식은 이와 같은 장단점이 존재하므로, 상황에 따라 맞는 방법을 사용해야 한다.
람다식과 익명클래스의 관계
익명클래스는 복잡하고 긴 자바 문법을 간결하게 하는 것에 초점을 둔다. 이러한 이유로 람다 표현식 문법과 매우 잘 어울리며, 실제로 함께 자주 쓰인다.
예를들어, 다음과 같은 익명 클래스에 람다 표현식을 적용한다면 코드를 아주 간결하게 작성할 수 있게 된다.
Operate operate = new Operate() {
public int operate(int a, int b) {
return a + b;
}
};
// 람다식 사용
Operate operate = (a, b) -> {
return a + b;
};
// return만 존재하므로 아래와 같은 표현이 가능
Operate operate = (a, b) -> a + b;
위의 내용을 람다 표현식의 문법 위주로 요약해서 정리해보자면, 아래와 같다.
// Usage
(타입 매개변수, 타입 매개변수2, ...) -> { 실행문; ... }
// example
(int a) -> {System.out.println(a);}
(a) -> { System.out.println(a); }
a -> System.out.println(a)
// 매개변수가 존재하지 않는 경우
() -> { 실행문; ... }
오늘은 익명클래스와 람다표현식에 대해 알아보았다.
오늘 미처 알아보지 못한 함수형 프로그래밍 / @FunctionalInterface / 스트림 API / 메소드 레퍼런스에 대해서 더 자세히 알아볼 예정이다.
참고
댓글을 작성해보세요.