람다 표현식?

람다 표현식은 간략하게 표현하면 익명 함수의 단순화입니다.

 

특징

1. 익명(이름 없음)으므로 작성할 코드량이 줄어듭니다.

2. 특정 클래스에 종속되지 않으므로 메서드 대신 함수라고 부르지만

    메서드 처럼 파라미터 리스트, 바디, 반환 형식, 예외 리스트를 포함합니다.

3. 람다 표현식은 메서드 인수로 전달하거나 변수에 저장 가능합니다.

 

기존 익명함수 사용한 코드

new Thread(new Runnable() {

    @Override
    public void run() {
        System.out.println("Thread Start");		
    }
}).start();
Comparator<Integer> num = new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o1.compareTo(o2);
    }
};

람다 표현식을 사용한 코드

new Thread(() -> System.out.println("Thread Start")).start();
Comparator<Integer> ramDaExpNum1 = (o1, o2) -> o1.compareTo(o2);
Comparator<Integer> ramDaExpNum2 = (Integer o1, Integer o2) -> o1.compareTo(o2);

람다 파라미터는 위와 같이 생략이 가능합니다.

 

함수형 인터페이스

함수형 인터페이스는 오직 하나의 추상 메서드만 가지는 인터페이스입니다.

public class Main {
	public static void main(String[] args) {
    		Concat c = (a, b) -> System.out.println(a+b);	
		c.concat("홍", "길동");
		c.concat("11월", "11일");
    	}
}

@FunctionalInterface 어노테이션

interface에 추가해주면 컴파일 시점에 해당 인터페이스가 규칙을 지키는지 검증합니다.

@FunctionalInterface
public interface Concat {
	void concat(String a, String b);
}

 

기본 제공 함수형 인터페이스 

Interface Descripter Abstract Method
Predicate T -> boolean boolean test(T t)
Consumer T -> void void accept(T t)
Supplier () -> T T get()
Function<T, R> T -> R R apply(T t)
Comparator (T, T) -> int int compare(T o1, T o2)
Runnable () -> void void run()
Callable () -> T V call()

 

함수형 인터페이스 사용

함수형 인터페이스의 추상 메서드의 시그니처는 람다 표현식의 시그너처를 나타냅니다.

람다 표현식의 시그니처를 서술하는 메서드를 함수 디스크립터(descriptor)라고 하고

추상 메서드의 시그니처와 함수 디스크립터가 같다면 함수형 인터페이스를 활용 가능합니다.

 

public class Main {
	public static void main(String[] args) {
		Runnable r1 = () -> System.out.println("Runnable" + 1);
		Runnable r2 = () -> System.out.println("Runnable" + 2);
		print(r1);
		print(r2);
	}
	
	public static void print(Runnable r) {
		 r.run();
	}
}

위와 같이 자주 변경되는 요구사항이 있다면 매번 메서드를 생성할 것이 아니라 변경하는 부분만 람다 함수로 만들어

활용이 가능합니다.

 

메서드 참조

메서드 참조를 사용하여 가독성을 높일 수 있습니다.

 

메서드 참조를 사용하지 않은 코드

public class Main {
	public static void main(String[] args) {
		List<String> list = Arrays.asList("a","b","A","B");
		list.sort((a, b) -> a.compareToIgnoreCase(b));
		for(String str : list) {
    		System.out.print(str);
		}
  	}
}

 

메서드 참조를 사용 코드

public class Main {
	public static void main(String[] args) {
		List<String> list = Arrays.asList("a","b","A","B");
		list.sort(String::compareTo);
		list.stream().forEach(System.out::print); // 스트림 사용
  	}
}

 

지역변수의 사용

외부에 정의된 변수를 사용할 수 있습니다. 이를 람다 캡쳐링이라고 합니다.

public class Main {
	public static void main(String[] args) {
		int num = 12345;
		Runnable r = () -> System.out.println(num);
        // 아래 주석 해제 시 에러 발생.
        // num = 123;
  	}
}

여기서 지역 변수는 final로 선언하거나 final 변수처럼 사용해야 합니다.

람다가 실행되는 스레드에서 변수를 할당한 스레드가 해제되었는데도 접근하려 할 수 있기 때문에

이 같은 제약이 있다고 합니다.

 

 

+ Recent posts