BE/Java

[Java 8] 람다식과 함수형 인터페이스

멍목 2024. 3. 10. 18:48
반응형

Java 8의 특징

  • Interface에 default 메서드, static 메서드 사용 가능
    • 자바 8 이전까지 Interface의 abstract 메서드는 반드시 클래스에서 구현했어야 함.
      • 인터페이스에 absrtact 메서드를 추가했다면, 그 인터페이스를 사용한 모든 클래스에서 그 메서드를 구현했어야 함 (바이너리 호환성 이슈)
    • 자바 8이후로 default, static 메서드 사용이 가능
  • 람다식 사용 가능, 람다를 이용해서 스트림API 사용 가능(람다는 Java8 기능 중 큰 변화)
  • Time, Date 관련한 API 추가

 

함수형 프로그래밍(Functional Programming)

  • 계산을 수학적 함수의 평가로 취급하고, 변경 불가능한 값을 이용
  • 함수형 프로그래밍은 순수 함수들로만 작성된다.
    • 순수함수 : 입력이 같으면 출력이 항상 같다.
  • 함수가 1등 시민
    • 1등 시민 : 함수를 변수나 자료구조 안에 담을 수 있고, 함수를 인자로 전달할 수도 있으며, 반환 값으로도 사용할 수 있다.
  • 람다와 클로저를 사용할 수 있다. (Stream도 가능)
    • 람다 : 익명함수를 의미, 클로저 : 자신이 생성될 때의 scope에서 알 수 있었던 변수를 기억하는 함수
  • 즉, 부수 효과가 없는 함수들로만 구축

 

함수형 프로그래밍의 목적

  • 불변 상태 변수를 이용해 부수 효과를 제거
  • 모든 것을 객체 취급
  • 코드를 간결하게 하여, 가독성을 높임
  • 동시성 작업을 보다 쉽고 안전하게 구현

 

 

부수 효과?

  • 변수를 수정하거나 객체 필드를 설정
  • 예외를 던지거나 오류를 내면서 실행을 중단
  • 콘솔에 입출력 / 파일 입출력

 

람다(Lambda)

  • 익명 : 함수에 이름이 없다.
  • 함수 : 메서드 처럼 특정 클래스에 종속되지 않는다. 파라미터 리스트, 바디, 리턴값을 포함 한다.
  • 전달 : 람다 표현식을 메서드의 인자로 전달하거나 변수 값으로 저장할 수 있다.
  • 간결성 : 익명 클래스를 처럼 부가 코드를 구현할 필요가 없다

 

ex 1-1) 일반적인 Java 표현식

Comparator<Integer> comparator = new Comparator<Integer>(){ 
	@Override 
	public int compare(Integer o1, Integer o2) { 
		return o2 - o1; 
	}
};

ex 1-2) Lambda 표현식

Comparator<Integer> comparator = (o1, o2) -> o2 - o1;

 

ex 2-1) Runnable 예(일반적인 Java)

public class AsyncHelloWorld {
	public static void main(String[] args){
		new Thread(new Runnable(){
			@Override
			public void run() {
				System.out.println(“Hello World”);
			}
		}).start();
	}
}

ex 2-2) Runnable 예(Lambda 표현식)

public class AsyncHelloWorld {
	public static void main(String[] args){
		new Thread(() -> {
			System.out.println(“Hello World”);
		}).start();
	}
}

 

람다 vs 익명클래스

익명 클래스는 컴파일 시, 서브클래스로 별도의 파일로 컴파일되고, 람다는 기존 클래스에 포함

 

 

람다 표현식의 예

  • 파라미터 타입지정 Comparator<Long> longComparator = (Long first, Long second) -> Long.compare(first,second);
  • 파라미터 타입지정, 문맥에서 유추 Comparator<Long> longComparator = (first, second) -> Long.compare(first,second);
  • 파라미터가 한 개인 경우, 파라미터 목록에 괄호 생략 Predicate<String> predicate = t -> t.length() > 10;
  • 파라미터가 없는 경우 Callable<String> callable = () -> “noparam”;
  • 결과 값이 없는 경우 Runnable runnable = () -> System.out.println(“no return”);
  • 코드 블록을 사용할 경우, return을 이용해서 결과 값을 리턴 Operator<Integer> plusOp = (op1,op2) -> { int result = op1 + op2; return result * resutl; }

 

 

함수형 인터페이스의 종류

 

함수형 인터페이스의 Default Method

  • negate() : 뒤집기(반대)
  • and()
  • or()
Predicate<Apple> redApple = a -> a.getColor().equals("red");

// negate() : Predicate 뒤집기
Predicate<Apple> notRedApple = redApple.negate();

// and() : red & weight > 150
Predicate<Apple> redHeavyApple = redApple.and(a -> a.getWeight() > 150);

 

andThen()과 compose() Default Method

  • consumer, Function, Operator 함수형 인터페이스는 andThen()과 compose() 디폴트 메서드를 가진다.
  • 두 개의 함수형 인터페이스를 순차적으로 연결하여 실행.
  • andThen()은 앞에 있는 함수형 인터페이스를 먼저 실행하며, compose()는 뒤에 있는 함수형 인터페이스를 먼저 실행한다.

 

Method Reference 종류

  • 메서드 참조의 목적 : 메서드를 참조해서 매개변수의 정보 및 리턴 타입을 알아내, 람다식에 불필요한 매개변수를 제거(간결하게)
정적 메서드 참조 클래스명::정적메서드명
객체 메서드 참조 객체변수::메서드명
람다인자 객체 메서드 참조 클래스명::메서드명
생성자 참조 클래스명::new

 

 

함수형 인터페이스 요약

  • 람다 표현식은 익명클래스를 간결하게 표현할 수 있다. (약간은 다르다)
  • 함수형 인터페이스는 추상 메서드 하나만 정의된 인터페이스이다.
  • Java에서는 자주 사용되는 기본적인 형태의 함수형 인터페이스를 제공한다.
  • 기본 제공되는 함수형 인터페이스는 Boxing을 피할 수 있도록 IntPredicate, IntToLongFunction과 같은 primitive 타입의 인터페이스를 제공한다.
  • 메서드 레퍼런스를 이용하면 기존의 메서드 구현을 재사용 및 전달 가능하다.
  • Comparator, Predicate, Function 같은 함수형 인터페이스는 람다 표현식을 조합 할 수 있는 다양한 디폴트 메서드를 제공한다
반응형