JAVA 8 부터, 현재 2022년 6월 기준 JAVA 16까지.
어떤 것이 변했는지 알아보자. 특히나 가장 혁신적으로 변했던 JAVA 8부터 살펴보자.
버전 |
기능 | 종류 | 설명 |
8 | Lambda Expression 및 Method Reference 도입 |
Language | anonymous inner class 표현 간략화 (함수형 표현) 인자로 method reference를 전달 (함수형 표현) |
8 | Collections & Streams | Language | Collections에서 Streams API를 사용하여, 이전의 반복문이 아닌 함수형 구현 |
8 | Interface Default Method 도입 | Language | interface 내부에서 default 메서드를 선언할 수 있다. |
8 | Optional Class 도입 | Language | Optional Class를 이용하여 NullPointerException이 발생하는 것을 방지해 준다. |
Lambda Expression
먼저, JAVA의 람다는 메소드를 하나의 식으로 표현한 것이다.
익명메소드 생성 문법이라 할 수 있다. 메소드명없이 구현부만으로 선언하는 것이다.
하지만 JAVA의 메소드는 메소드 자체로 혼자 선언하여 쓰일 수 없다. 무조건 Class 구성멤버로 선언되어야 한다.
람다식을 통해서 생성되는 것은 메소드 자체가 아닌 실행문을 가진 객체이다.
람다식은 일반적인 객체가 아닌 인터페이스를 구현한 익명구현객체를 생성한다.
예제를 통해서 알아보자.
interface Calculator {
public int add(int n) ;
}
Calculator라는 인터페이스는 add()라는 추상메소드를 가지고 있다. Calculator를 객체화하는 방법은 두 가지이다.
- implements한 class를 생성
- 익명 클래스로 생성
아래는 익명클래스로 생성하여 add 라는 메소드를 구현하여 사용한 방법이다.
public class Lambda {
public static void main(String[] args) {
// 생성과 동시에 구현할 메소드를 override 한다.
// 익명 클래스로 선언
Calculator cal1 = new Calculator() {
@Override
public int add(int n) {
return n + 1;
}
};
System.out.println(cal1.add(2)); // 3
}
}
위의 코드는 아래의 람다식으로 변경할 수 있다.
public class Lambda {
public static void main(String[] args) {
// (매개변수) -> {구현로직}
// 람다식으로 선언
Calculator cal2 = (int n) -> {return n + 1;};
System.out.println("cal 2 = " + cal2.add(2)); // 3
}
}
Runtime 시에 해당 매개변수의 값이 자동으로 결정되므로, 아래 처럼 변경 가능하다.
public class Lambda {
public static void main(String[] args) {
// (매개변수) -> {구현로직}
// 람다식으로 선언
// runtime 시에 매개변수 값이 정해지므로, n에 대한 변수타입 생략가능
Calculator cal2 = (n) -> {return n + 1;};
System.out.println("cal 2 = " + cal2.add(2));
}
}
매개 변수가 1개일 경우 () 생략 가능하다.
public class Lambda {
public static void main(String[] args) {
// (매개변수) -> {구현로직}
// 람다식으로 선언
// runtime 시에 매개변수 값이 정해지므로, n에 대한 변수타입 생략가능
// 매개 변수가 1개이므로 () 생략가능.
// 매개 변수가 없는 경우에는 () 생략불가. ex) () -> 표현식
Calculator cal2 = n -> {return n + 1;};
System.out.println("cal 2 = " + cal2.add(2));
}
}
위에서 말했듯이, 컴파일러는 람다식을 해석하여 자동으로 익명구현객체로 만든다.
이 때 람다식의 타겟 타입이 될 인터페이스는 2개 이상의 추상 메소드를 가지면 안된다.
그렇게 되면 컴파일러가 해당 람다식이 타겟 타입의 어떤 메소드를 구현한 것인지 알 수 없기 때문이다.
@FuntionalInterface는 이것을 명시적으로 선언하고 강제하는 어노테이션이다.
이런식으로 선언된 인터페이스를 람다식의 함수적 인터페이스 라 한다.
@FuntionalInterface 란?
위에서 말한 바와 같이 함수형 인터페이스로 람다식을 사용하기 위해서는 해당 인터페이스가 단 하나의 추상메소드를 가져야 한다.
실수로라도 다른 사람이 해당 인터페이스에 다른 메소드를 추가하거나 하면, 에러를 발생시키기 위해 명시적으로 선언하는 것이다.
//good
@FunctionalInterface
public interface Foo {
String method();
}
//bad
public interface Foo {
String method();
}
다음 글에서는 Method Reference 에 대해서 알아보자.
https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html
'Backend > Java' 카테고리의 다른 글
멀티쓰레드 프로그램이 뭘까? with 자바 동기화(monitor) (0) | 2023.02.11 |
---|---|
Mac Java 설치 및 버전 여러개 관리 deprecated adoptopenjdk (0) | 2023.01.10 |
RESTFul 하다는 건 뭘까? (0) | 2022.04.05 |
전략 패턴(Strategy Pattern) 예제 코드로 이해하기 (0) | 2022.04.04 |
파사드 패턴(Facade Pattern) 예제 코드로 이해하기 (0) | 2022.04.03 |