728x90
반응형
SMALL
람다 표현식
- Java8 부터 도입
- 추상메소드가 하나뿐인 인터페이스를 Override를 통해 구현
- 이를 함수형 인터페이스 (Functional Interface) 라고 부름
- 익명 클래스 (관련 설명은 여기에[내부 클래스]) 의 더 간략한 표현식이라고 볼 수 있다.
- 메소드를 간결한 함수 식으로 표현한 것으로 메소드의 이름, 반환값을 생략할 수 있기 떄문에 코드가 매우 간결해진다는 장점
- 한번 사용하고 버려질 클래스 라면, 선언 하지 않고 일회성 오버라이딩으로 사용 가능
- 예시
int add(int a, int b) {
return a + b;
}
//아래와 같이 간단한 두 매개변수를 더하는 함수를 람다식으로 표현할 수 있다.
(a, b) -> {return a+b;}
- 문법이 매우 짧아 지는 것을 확인 할 수 있다.
- 람다 식을 통해 가독성이 좋아지고 특히 Collection Framework (관련 글) 를 사용 할 때, 요소를 필터링 하거나 정렬 되는 방식을 지정해 줄 수 있다.(Compareable)
람다 표현식 문법
- 매개변수의 타입은 생략해서 표현이 가능
- 매개변수가 여러개 있을 경우
- 모든 매개변수의 타입을 생략해서 표현하거나
- 모든 매개변수의 타입을 모두 다 표현해야 함.
- 밑에 예시에서는 모든 타입들을 생략하도록 하겠음
// 소괄호 생략 가능 과정
(a) -> {System.out.println(a);} // 매개변수가 한개일 때는 소괄호 생략 가능
a -> {System.out.println(a);} // 가능
(a,b) -> {System.out.println(a+b);} //매개 변수가 두개일때는 소괄호 생략 불가능
a,b -> {System.out.println(a+b);} //불가능
() -> {System.out.println("안녕?");} // 매개변수가 없는 경우에는 생략 불가능
- 매개변수가 하나일 때만, 소괄호 생략 가능하다.
// 중괄호 생략 가능 문법
// 보통 하나의 문장으로만 이루어진 코드는 중괄호를 생략 할 수 있다 라는 표현을 사용
(a)-> {return a+1;} //중괄호 안에 구현 코드가 return 문만 존재할 때 중괄호와 return 을 생략 가능
(a) -> a+1; //가능
(a) -> System.out.println(a); //가능 리턴값이 없는 void 일 때 가능
//메소드의 반환 타입이 void가 아닌경우 혹은 안에 return 문만 있는 것이 아닐때에는 중괄호를 생략할 수 없다.
(a) -> { //불가능
if (a > 0){
return -1;
}else {
return 1;
}
}
- 중괄호는 하나의 문장일때 만 생략이 가능하다.
람다 식에 관련 되어서 아래 3가지 방법으로 구현 하는 방법이 있다.
1. 클래스이름 implements 인터페이스이름 + 함수 오버라이드 & 구현
2. 익명 클래스를 통한 구현
3. 람다 표현식을 통한 구현
함수형 인터페이스 란? @FunctionalInterface? [java.util.function]
- 함수형 인터페이스란 딱 하나의 추상 메소드가 선언된 인터페이스를 말한다.
- 람다식을 사용하기 위해서는 인터페이스에 두개 이상의 추상 메소드가 선언되어 있으면 안된다
- 어떤 메소드를 사용하고자 하는지 알 수 없기 때문에 사용할 수 없다.
- 생각해보면 당연한 거였는데 본인은 꽤 오래 생각했던거 같다.
- @FuntionalInterface는 람다식으로 표현 가능한 함수형 인터페이스를 만들 때, 두 개 이상의 메소드가 선언 되면 컴파일러가 확인해주는 기능을 지원한다.
- 예를들어 어노테이션이 걸려있는 이 부분에 추상 메소드를 두개를 선언하면 컴파일 오류를 발생 시켜준다는 것이다.
- 개발자들 한테 참 좋다고 한다.
- 예를들어 어노테이션이 걸려있는 이 부분에 추상 메소드를 두개를 선언하면 컴파일 오류를 발생 시켜준다는 것이다.
자바에서 제공하는 기본적인 함수형 인터페이스 [ java.util.function ] |
|
Runnable | 매개변수 없음. return type : void |
Supplier<T> | 매개변수 없음. return type : T |
Consumer<T> | 매개변수 type: T return type : void |
Function<T, R> | 매개변수 type: T return type : R |
Predict<T> | 매개변수 type: T return type : T |
UnaryOperator<T> | 매개변수 type: T (2개) return type : T |
BinaryOperator<T> | 매개변수 type: T (2개) return type : T |
BiPredict<T, U> | 매개변수 type: T,U (서로 다른 타입 2개) return type : Boolean |
BiConsumer<T, U> | 매개변수 type: T , U (2개) return type : void |
BiFunctional<T, U, R> | 매개변수 type: T,U (서로 다른 타입 2개) return type : R |
Comparator<T> | 자바의 전통적인 인터페이스중 하나 매개변수 type: T (2개) return type : int |
// Runnable
{
Runnable r = () -> System.out.println("hello functional");
r.run(); //hello functional
}
// Supplier<T>
{
Supplier<String> s = () -> "hello supplier";
String result = s.get();
System.out.println(result); //hello supplier
}
// Consumer<T>
{
Consumer<String> c = str -> System.out.println(str);
c.accept("hello consumer"); //hello consumer
}
// Function<T, R>
{
Function<String, Integer> f = str -> Integer.parseInt(str);
Integer result = f.apply("1");
System.out.println(result); // 1
}
// Predicate<T>
{
Predicate<String> p = str -> str.isEmpty();
boolean result = p.test("hello");
System.out.println(result); // false
System.out.println(p.test("")); // true
}
// UnaryOperator<T>
{
UnaryOperator<String> u = str -> str + " operator";
String result = u.apply("hello unary");
System.out.println(result); //hello unary operator
}
// BinaryOperator<T>
{
BinaryOperator<String> b = (str1, str2) -> str1 + " " + str2;
String result = b.apply("안녕", "얘들아");
System.out.println(result); //안녕 얘들아
}
// BiPredicate<T, U>
{
BiPredicate<String, Integer> bp = (str, num) -> str.equals(Integer.toString(num));
boolean result = bp.test("1", 1);
System.out.println(result); //true
}
// BiConsumer<T, U>
{
BiConsumer<String, Integer> bc = (str, num) -> System.out.println(str + " :: " + num);
bc.accept("숫자", 5); //숫자::5
}
// BiFunction<T, U, R>
{
BiFunction<Integer, String, String> bf = (num, str) -> String.valueOf(num) + str;
String result = bf.apply(5, "678");
System.out.println(result); //5678
}
// Comparator<T>
{
Comparator<String> c = (str1, str2) -> str1.compareTo(str2);
int result = c.compare("aaa", "bbb");
System.out.println(result); //-1
}
Method Reference (메소드 레퍼런스)
- 람다 표현식에서 '메소드 1회'로 코드가 끝나는 경우 메소드 레퍼런스를 이용하면 코드가 훨씬 간략해 진다.
- static 메소드 레퍼런스
- 호출하고자 하는 정적 클래스::메소드
- 매개변수의 인스턴스 메소드 레퍼런스
- 매개변수 타입이 명확할때 해당 타입 클래스::메소드
- 생성자 메소드 생성
- 리턴해야하는 타입명::new
- 외부 인스턴스 메소드 레퍼런스
- 람다 캡처링을 이용해서 람다표현식 바깥에 있는 인스턴스의 메소드를 호출 할때 사용
- 본인은 람다식을 통해 있는 변수를 람다식 구현파트에 사용하는 것이라고 생각
- 하지만 사용되는 변수는 effective final (이유는 익명 클래스를 사용하는 것이기 때문에! 위에 내부 클래스 링크를 타고 가면 있음)
- static 메소드 레퍼런스
{
//static 메소드 레퍼런스
Consumer<String> consumer = System.out::println;
consumer.accept("static method reference")
}
{
//인스턴스 메소드 레퍼런스
UnaryOperator<String> unary = String::toUpperCase;
System.out.println(unary.apply("hihi")); //HIHI
}
{
//생성자 메소드 레퍼런스
String s = String::new;
}
{
//외부 인스턴스 temp 선언
String temp = "안녕하세요?";
//외부 캡쳐링! (람다 식 내부에서 외부 인스턴스를 참조)
Predict<String> predict = temp::equals;
System.out.println(predict.test("아니?")); //false
}
728x90
반응형
LIST
'프로그래밍 > 자바' 카테고리의 다른 글
[자바/기본] Stream 이란? (0) | 2024.02.20 |
---|---|
[자바/기본] Optional 이란? (0) | 2024.02.19 |
[자바/기본] 내부 클래스(InnerClass) (0) | 2024.02.14 |
[자바/기본] List 란? (0) | 2024.02.13 |
[자바/기본] Collection Framework란? (0) | 2024.02.11 |