-
728x90
람다식 - 메서드를 하나의 식 으로 표현하는 것이다. ( 메서드의 이름과 반환값이 없어지므로, 익명함수다 )
간단한 람다식 예시
int method() { return (int)(Math.random() * 5 ) + 1; } int[] arr = new int[5]; Arrays.setAll(arr, (i) -> (int)(Math.random() * 5 ) + 1 ); // 바로 윗부분이 람다식이다.
람다식 작성하기
'익명 함수' 답게 매개변수 선언부와 몸통 { } 사이에 '->'를 추가한다
반환타입 메서드이름(매개변수 선언) { 문장들 } (매개변수 선언) -> { 문장들 }
return문 대신 식으로 할 수 있는데, 잌대는 끝에 ; 을 붙이지 않는다.
람다식에 선언된 매개변수의 타입은 추론이 가능한 경우는 생략할 수 있는데, 대부분의 경우 생략 가능하다.
람다식에 반환타입이 없는 이유도 항상 추론이 가능하기 떄문이다.
(int a, int b) -> a > b ? a : b -> (a,b) -> a > b ? a : b
매개변수가 하나뿐인 경우에는 괄호()를 생략할 수 있다. 단, 매개변수의 타입이 있으면 ( )를 생략할 수 없다.
(a) -> a * a => a -> a * a (int a) -> a * a => int a -> a * a // 에러
괄호 { }안의 문장이 하나일 때 괄호 { } 를 생략할 수 있다 ( 문장의 끝에 ';' 을 붙이지 않아야 한다. )
(String name, int i) -> { System.out.prinln(name + "=" + i); } (String name, int i ) -> System.out.prinln(name + "=" + i)
{ }안의 문장이 return 문일 경우에는 { }를 생략할 수 없다.
(int a, int b) -> { return a > b ? a : b } (int a, int b) -> return a > b ? a : b // error
람다식을 이해하기 좋은 람다식의 예제들
메서드 람다식 int max( int a,int b ) {
return a>b ? a : b;
}(a, b) -> a > b ? a : b void printVar(String name, int i) {
System.out.println ( name + "=" + i )
}(name, i) ->
System.out.println(name+"="+i);int square(int x) {
return x*x;
}x -> x * x int roll() {
return (int)(Math.random() * 6);
}() -> (int)(Math.random() * 6 ); int sumArr(int[] arr) {
int sum = 0;
for(int i : arr)
sum += i;
return sum;
}(int[] arr) -> {
int sum = 0;
for(int i : arr)
sum += i;
return sum;
}함수형 인터페이스
람다식은 익명 클래스의 객체와 동등하다 -> 참조변수가 있어야 객체의 메서드를 호출할 수 있으니 익명객체의 주소를 참조변수에 저장해야한다
타입 f = (int a ,int b) -> a > b ? a : b;
타입은 클래스 또는 인터페이스 여야 한다.
interface MyFunction { public abstract int max(int a, int b); } // 익명 함수 MyFunction f = new MyFunction() { public int max(int a, int b ) { return a > b ? a : b; } }; int big = f.max(5,3); // 익명 객체의 메서드 호출 // 람다식 MyFunction f = (int a, int b) -> a > b ? a : b; MyFunction // 익명 객체의 메서드 호출
함수형 인터페이스 - 람다식을 다루기 위한 인터페이스
함수형 인터페이스는 오직 하나의 추상메서드만 정의되어 있어야 한다.
반면에, static, default 메서드는 개수에 젝약이 없다
@FunctionalInterface interface MyFunction { // 함수형 인터페이스 MyFunction을 정의 public abstract int max(int a, int b); }
기존 인터페이스 메서드 하나 구현 하는 방법 vs 람다식으로 구현
List<String> list = Arrays.asList("aa","bb"); Collections.sort(list, new Comparator<String>() { public int compare(String s1, String s2) { return s2.compareTo(s1); } }); List<String> list = Arrays.asList("aa", "bb"); Collections.sort(list, (s1,s2) -> s2.compareTo(s1));
함수형 인터페이스 타입의 매개변수와 변환타입
메서드를 호출할 때 람다식을 참조하는 참조변수를 매개변수로 지정하는 방법
void aMethod(MyFunction f) { f.myMethod(); } ... MyFunction f = () -> System.out.println("MyMethod()"); aMethod(f);
참조변수 없이 직접 람다식을 매개변수로 지정하는 방법
aMethod(() -> System.out.println("MyMethod()"));
람가싣을 참조변수로 다룰 수 있다는 것은 메서드를 통해 함다식을 주고받을 수 있다는 것을 의미한다.
-> 변수처럼 메서드를 주고받는 것이 가능해진 것이다.
람다식의 타입과 형변환
람다식의 타입이 함수형 인터페이스의 타입과 일치하느 것은 아니다.
따라서 대입 연산자의 얀변의 타입을 일치시키기 위해 형변환이 필요하다.
MyFuntion f = (MyFuntion)( () -> {});
주의
1. 형변환은 생략가능하다
2. Object타입으로 형변환이 불가능하고, 오직 함수형 인터페이스로만 형변환이 가능하다- 람다식 내에서 참조하는 지역변수는 final이 붙지 않았어도 상수로 간주된다.
- 외부지역변수와 같은 이름의 람다식 매개변수는 허용되지 앟는다
java.util.function 패키지
T = Type, R = Return Type
주요 함수형 인터페이스 조건식에 사용되는 Predicate
Predicate - Function의 변형으로 반환타입이 boolean이라는 것만 다르다.
Predicate<String> isEmptyStr = s -> s.length() == 0; String s = ""; if(isEmptyStr.test(s)) // if (s.length == 0) System.out.println("empty string");
매개변수가 2개인 함수형 인터페이스
매개변수가 2개면 이름 앞에 'Bi' 가 붙는다.
3개의 매개변수를 갖는 함수형 인터페이스를 선언하는 예시
@FunctionalInterface interface TriFunction<T,U,V,R> { R apply(T t, U u, V v); }
UnaryOperator, BinaryOperator
둘다 매개변수의 타입과 변환타입의 타입이 모두 일치한다는 점만 제외하고는 Function과 같다
operator 매개변수의 타입과 반환타입이 일치할 때는 Funtion대신 UnaryOperator 사용하기
기본형을 사용하는 함수형 인터페이스
기본형을 사용하는 함수형 인터페이스 Funtion의 합성과 Predicate의 결합
람다식도 다른 람다식과 합성해서 새로운 람다식을 만들 수 있다.
Funtion default <V> Funtion<T,V> andThen(Funtion<? super R, ? extends V>after) default <V> Funtion<T,V> compose(Funtion<? super V, ? extends T>before) static <V> Funtion<T,T> identity() Predicate default Predicate<T> and(Predicate<? super T> other) default Predicate<T> or(Predicate<? super T> other) default Predicate<T> negate() static <T> Predicate<T> isEqual(Object targetRef)
Funtion합성 - andThen( )예시
Function<String, Integer> f = (s) -> Integer.parseInt(s,16); Function<Integer, String> g = (i) -> Integer.toBinaryString(i); Function<String, String> h = f.andThen(g)
Predicate합성 - and(), or(), negate()로 연결
Predicate<Integer> p = i -> i < 100; Predicate<Integer> q = i -> i < 200; Predicate<Integer> r = i -> i%2 == 0; Predicate<Integer> notP = p.negate(); // i >= 100 // 100 <= i && (i < 200 || i%2 == 0) Predicate<Integer> all = notP.and(q.or(i)); System.out.println(all.test(150)); // true // 람다식으로 가능 Predicate<Integer> all = notP.and(i -> i < 200).or(i -> i%2 == 0);
메서드 참조
메서드 참조 - 람다식이 하나의 메서드만 호출하는 경우에 좀 더 간결하게 코드 표현 가능
하나의 메서드만 호출하는 람다식은 '클래스이름::메서드이름' 또는 '참조변수::메서드이름' 으로 바꿀 수 있다.
종류 람다 메서드 참조 static메서드 (x) -> ClassName.method(x) ClassName::method 인스턴스메서드 (obj.x) -> obj.method(x) ClassName::method 특정 객체 인스턴스메서드 (x) -> obj.method(x) obj::method Integer wrapper(String s) { // 메서드 명은 상관없움 return Integer.parseInt(s); } // 람다 Funtion<String, Integer> f = (String s) -> Integer.parseInt(s); // 메서드 참조 Funtion<String, Integer> f = Integer::parseInt;
생성자의 메서드 참조
Supplier<MyClass> s = () -> new MyClass(); // 람다식 Supplier<MyClass> s = MyClass::new; // 메서드 참조 Function<Integer, MyClass> f = (i) -> new MyClass(i); // 람다식 Function<Integer, MyClass> f2 = MyClass::new; // 메서드 참조 BiFunction<String, Integer, MyClass> bf = (i,s) -> new MyClass(i,s); // 람다식 BiFunction<String, Integer, MyClass> bf2 = MyClass::new; // 메서드 참조 // 배열 Function<Integer, int[]> f = x -> new int[x]; // 람다식 Function<Integer, int[]> f2 = int[]::new; // 메서드 참조
'자바' 카테고리의 다른 글
[자바] 입출력 (0) 2022.07.26 [자바] 스트림 (0) 2022.07.25 [자바] 쓰레드 (0) 2022.07.23 [자바] 애너테이션 (0) 2022.07.23 [자바] 열거형 ( enum ) (0) 2022.07.23