본문 바로가기

Java/기초

[Java] 람다식(Lambda expression)

하나의 메서드만 포함하는 익명 클래스의 경우 구문이 다루기 어렵고 불문명해 보이는 문제가 있다. 이 문제를 해결하기 위해서 Lambda Expression을 사용하면 메서드 인수, 코드를 데이터로 처리할 수 있다.

Lambda Expression을 사용하면 단일 메서드 클래스의 인스턴스를 보다 간결하게 표현할 수 있다.

 

Lambda Expressions (The Java™ Tutorials > Learning the Java Language > Classes and Objects)

The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Java Language Changes for a summary of updated

docs.oracle.com

 

Stream 연산들은 매개변수로 함수형 인터페이스(Functional Interface)를 받도록 되어있다. 그리고 람다식은 반환값으로 함수형 인터페이스를 반환하고 있다. 그렇기 때문에 우리는 Stream API를 정확히 이해하기 위해 람다식과 함수형 인터페이스에 대해 알고 있어야 한다.

 

자바 등장 후 두 번의 큰 변화

메서드를 람다식으로 표현하면 메서드의 이름과 반환값이 없어지므로, 람다식을 '익명 함수(anonymous function)'이라고 한다.메서드의 인수로 전달될 수 있고, 변수도 저장될 수도 있다.

※ 메서드는 특정 클래스에 반드시 속해야 한다는 제약이 있다. 람다식을 통해 메서드가 하나의 독립적인 기능을 하기 때문에 함수라는 용어를 사용하게 되었다.

// 기존의 방식 반환티입 메소드명
(매개변수, ...) { 실행문 } 

// 예시 
public String hello() { return "Hello World!"; }


// 람다 방식 
(매개변수, ... ) -> { 실행문 ... } 

// 예시 
() -> "Hello World!";
  • 람다식의 장단점
    • 장점
      • 코드를 간견하게 만들 수 있다.
      • 코드에 개발자의 의도가 명확히 드러나므로 가독성이 향상된다.
      • 함수를 만드는 과정없이 한번에 처리할 수 있기에 코딩하는 시간이 줄어든다.
      • 병렬프로그래밍이 용이하다.
    • 단점
      • 람다를 사용하면서 만드는 무명함수는 재사용이 불가능하다.
      • 람다를 남발하면 코드가 지저분 해 질 수있다.(비슷한 함수를 계속 중복 생성할 가능성이 높음,오히려 코드를 이해하기 어려울 수 있다.)
      • 디버깅이 다소 까다롭다.
      • 모든 원소를 전부 순회하는 경우 람다식이 조금 느리다.
  • 람다식의 특징
    • 람다식은 0개 이상의 매개 변수를 가질 수 있다.
    • 매개 변수의 형식을 명시적으로 선언 할 수 있다.
    • 매개 변수는 괄호로 묶이고 쉼표로 구분된다.
    • 빈 괄호는 매개 변수가 없음을 나타낸다.
    • 단일 매개 변수이고 타입은 유추가 가능한 경우에는, 괄호를 사용할 필요는 없다.
    • 람다식의 본문에는 0개 이상의 문장이 포함 될 수 있다.
    • 람다식의 본문은 단일 문장일 경우 중괄호는 없어도 되며 반환 형식은 일반적은 함수와 동일하다.
    • 본문에 하나 이상의 문장이 있으면 중괄호로 묶어야 한다.

함수형 인터페이스(Functional Interface)

@FunctionalInterface
public interface CalcIn {
    void run();
}
...

MyFunction3 f3 = () -> System.out.println("f3.run()");
  • 람다식을 다루기 위한 인터페이스
  • 함수형 인터페이스를 사용하는 이유
    1. 람다식은 함수형 인터페이스로만 접근이 되기 때문이다.
      • Java의 람다식이 함수형 인터페이스를 반환한다.
    2. 람다식이 메서드와 동등하지만, 익명 클래스의 객체와 동등하다.
    3. 변수처럼 네서드를 주고받을 수 있다.
  • 함수형 인터페이스의 특징
    • 오직 하나의 추상 메서드만 정의되어 있어야 한다
    • static메서드와 default메서드의 개수에는 제약이 없다
    • @FunctionalInterface 어노테이션
      • 해당 인터페이스가 함수형 인터페이스 조건에 맞는지 검사해준다.

기본 함수형 인터페이스(java.util.function 패키지)

대부분의 메서드는 타입이 비슷하다. 게다가 지네릭 메서드로 정의하면 매개변수나 반환 타입이 달라도 문제가 되지 않는다. 그래서 java.util.function패키지에 자주 쓰이는 형식의 메서드를 함수형 인터페이스로 미리 정의해 놓았다.

이 패키지의 함수형 인터페이스를 사용해야 메서드 이름도 통일되고, 재사용성과 유지보수 측면에서 좋다.

  • java.lang.Runnable : 매개변수 없고, 반환값도 없음
  • Supplier : 매개변수 없고, 반환값만 있음
  • Consumer : 매개변수 있고, 반환값 없음
  • Function<T, R> : 일반적인 함수, 하나의 매개변수가 있고, 매개변수를 받아서 결과를 반환
  • Predicate : 조건식을 표현하는데 사용됨, 매개변수는 하나, 반환타입은 boolean

메서드 참조(Method Reference)

  • 람다식이 하나의 메서드만 호출하는 경우에는 '메서드 참조'라는 방법으로 람다식을 간략히 할 수 있다.
  • 함수형 인터페이스를 람다식이 아닌 일반 메소드를 참조시켜 선언하는 방법이다.
  • 람다식을 마치 static변수처럼 다룰 수 있게 해준다.

1. static 메서드 참조

Function<String, Integer> f = (String s) -> Integer.parseInt(s);
Function<String, Integer> f2 = Integer::parseInt;//static 메서드 참조

컴파일러는 생략된 부분을 우변의 parseInt메서드의 선언부로 부터, 또는 좌변의 Functional인터페이스에 지정된 지네릭 타입으로부터 쉽게 알아낼 수 있다.

2. 인스턴스메서드 참조

public static boolean sample(String sample){
	return true;
}

main ...
Function<String, Boolean> f7 = MethodReferenceEx01::sample;//메서드 참조

참조변수(f3, f4)의 타입만 봐도 람다식이 두 개의 String타입의 매개변수를 받는 다는 것을 알 수 있으므로, 람다식의 매개변수들은 없어도 된다.

매개변수 s1, s2를 생랻하면 equals만 남는데, 두 개의 String을 받아서 Boolean을 리턴하는 equals라는 이름의 메서드는 다른 클래스에도 존재할 수 있기 때문에 equals앞에 클래스 이름은 반드시 필요하다.

3. 특정 객체 인스턴스메서드 참조

MethodReferenceEx01 obj = new MethodReferenceEx01();
Function<String, Boolean> f5 = (x) -> obj.equals(obj);//람다식
Function<String, Boolean> f6 = obj::equals;//특정 객체 인스턴스메서드 참조

이미 생성된 객체의 메서드를 람다식에서 사용한 경우에는 클래스 이름 대신 그 객체의 참조변수를 적어줘야 한다.

  • 참조 가능한 메소드는 일반 메소드, Static 메소드, 생성자가 있으며
    • '클래스이름 :: 메소드 이름' 으로 참조할 수 있다.

 

출처 : 

https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

 

Lambda Expressions (The Java™ Tutorials > Learning the Java Language > Classes and Objects)

The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Java Language Changes for a summary of updated

docs.oracle.com

 

https://github.com/oss0202/standardOfJava/tree/master/src/lambda

 

GitHub - oss0202/standardOfJava: Java의 정석을 읽으면서 작성한 코드들 입니다.

Java의 정석을 읽으면서 작성한 코드들 입니다. Contribute to oss0202/standardOfJava development by creating an account on GitHub.

github.com