1. 람다 함수(Lambda Function)란?
람다 함수는 함수형 프로그래밍 언어에서 사용되는 개념으로 익명 함수라고도 한다.
Java 8 부터 지원되며, 불필요한 코드를 줄이고 가독성을 향상시키는 것을 목적으로 두고있다.
2. 람다 함수의 특징
- 메소드의 매개변수로 전달될 수 있고, 변수에 저장될 수 있다.
즉, 어떤 전달되는 매개변수에 따라서 행위가 결정될 수 있음을 의미한다. - 컴파일러 추론에 의지하고 추론이 가능한 코드는 모두 제거해 코드를 간결하게 한다.
3. 람다식 표현
- 파라미터와 몸체로 구분된다.
- 파라미터와 몸체 사이에 -> 구분을 추가하여 람다식을 완성시킨다.
- 몸체 부분이 단일 행일 경우 중괄호와 return문을 생략할 수 있다.
( 파라미터 ) -> { 몸체 }
4. 익명함수를 람다식으로 변경하기
기존 방법
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Thread!");
}
}).start();
람다식
new Thread(() -> {
System.out.println("Thread!");
}).start();
기존의 방식은 Thread 사용 시 Runnable 인터페이스를 익명함수로 구현하였지만, Java 1.8부터 람다 함수을 통해 구현할 수 있게 되었다.
람다 함수를 매개변수로 넘기기 위해서는 메소드의 매개변수가 @FunctionalInterface로 선언된 인터페이스여야한다.
@FunctionalInterface이 선언된 인터페이스를 함수 인터페이스라 불리는데, 조건으로 반드시 추상 메소드 한개만 정의되어 있어야 한다.
그러면 람다식을 매개변수로 저장한 Runnable 인터페이스는 함수형 인터페이스일까?
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
Runnable 인터페이스를 보면 @FunctionalInterface와 한개의 추상메소드가 선언되어 있다.
즉, 함수형 인터페이스 조건에 성립하는 것이다.
5. 함수형 인터페이스
함수형 인터페이스의 조건
- @FunctionalInterface 어노테이션을 선언해야한다.
- 추상 메소드가 한개만 선언되어야한다.
- interface로 선언되어야한다.
이렇게 람다식을 위한 함수형 인터페이스 선언 조건에 대해서 알아보았다.
하지만 Java의 함수형 프로그래밍에는 큰 단점이 있다. 그것은 함수형 인터페이스 안에 선언된 메소드에 종속되는 람다식 밖에 구현할 수 없다는 점이다. 그래서 매개변수의 타입과 개수, 반환 값의 유무 등을 가진 메소드를 하나의 함수형 인터페이스로 구현할 수 없고, 필요한 동작에 따라서 함수형 인터페이스를 만들어줘야한다.
하지만 자바에서 우리가 사용할만한 함수형 인터페이스를 미리 정의해두었다.
- Suplier<T>
- Consumer<T>
- Function<T,R>
- Predicate<T>
1). Suplier<T>
매개 변수는 없고, 반환 값이 있는 함수형 인터페이스이다.
추상 메소드 T supplier()를 가진다.
Supplier<String> supplier = () -> "Hello World!";
System.out.println(supplier.get());
2). Consumer<T>
객체 T를 매개 변수로 받아서 소비한다. 반환 값은 없다.
추상메소드 void accpet(T t)를 가진다.
Consumer<String> consumer = (str) -> {
System.out.println(str);
};
consumer.accept("Hello World!");
3). Function<T,R>
객체 T를 매개 변수로 받아 처리 후 R로 반환한다.
추상메소드 R apply(T t)를 가진다.
Function<String, Integer> function = (str) -> {
return str.length();
};
System.out.println(function.apply("Hello World!"));
4). Predicate<T>
객체 T를 매개 변수로 받아 처리 후 Boolean으로 반환한다.
추상메소드 Boolean test(T t)를 가진다.
Predicate<String> predicate = (String str) -> {
return "Hello World!".equals(str);
};
System.out.println(predicate.test("Hello !!"));
위 코드는 단순 예시이고, 더 다양한 함수형 인터페이스가 제공되고 있다. 자세한 사항은 아래 사이트에서 참고하기 바란다.
https://docs.oracle.com/javase/8/docs/api/index.html?org/w3c/dom/Document.html
6. 메소드 참조(Method Reference)
메소드 참조란 함수형 인터페이스에 람다식이 아닌 일반적으로 사용하는 메소드를 참조시키는 방법이다.
참조 조건으로는 함수형 인터페이스의 매개변수 타입과 개수, 반환형이 참조하려는 메소드와 일치해야 한다.
참조 가능한 메소드는 다음과 같다.
- 일반 메소드
- static 메소드
- 생성자
1) 일반 메소드 ( ClassName::MethodName )
Consumer<String> consumer = System.out::println;
consumer.accept("Hello World!!");
위에 선언된 consumer는 void accept(String s) 메소드를 참조할 수 있다 그리고 System.out.println()는 void println(String str)로 선언된 메소드이다. 그래서 consumer는 println 메소드를 :: 연산자를 통해 참조 가능하다.
이를 이용해 다음과 같은 연산도 가능해진다.
List<String> list = Arrays.asList("red", "orange", "yellow", "green", "blue", "indigo", "purple");
list.forEach(System.out::println);
forEach 메소드는 Consumer 함수형 인터페이스를 인자로 받고 있다.
//interface Iterable<T>
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
2) Static 메소드( ClassName::StaticMethod )
Predicate<Boolean> predicate = Objects::isNull;
3) 생성자 ( ClassName::new )
Supplier<String> supplier = String::new;
'IT > JAVA' 카테고리의 다른 글
[JAVA] 배열 설명 및 초기화 방법 (0) | 2020.07.09 |
---|---|
[Java] Windows 10 Open-JDK 8 다운로드 및 환경변수 설정 (0) | 2020.04.07 |
[JAVA] Java 란? (0) | 2020.03.03 |
[JAVA] String 메소드 정리 (0) | 2019.12.18 |
[JAVA] LocalDateTime, LocalDate, LocalTime 정리 (0) | 2019.12.18 |