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

 

FunctionalInterface (Java Platform SE 8 )

An informative annotation type used to indicate that an interface type declaration is intended to be a functional interface as defined by the Java Language Specification. Conceptually, a functional interface has exactly one abstract method. Since default m

docs.oracle.com

https://www.baeldung.com/java-8-lambda-expressions-tips

 

Lambda Expressions and Functional Interfaces: Tips and Best Practices | Baeldung

Tips and best practices on using Java 8 lambdas and functional interfaces.

www.baeldung.com

+ Recent posts