19.04.18 람다식

Back-End/Java 2019. 4. 18. 18:08
728x90
반응형

-람다식-


람다식을 사용하는 이유는 자바 코드가 매우 간결해지고, 컬렉션의 요소를 필터링 하거나 매핑해서 원하는 결과를 쉽게 집계할 수 있기
때문이다.

Runnable 인터페이스의 익명 구현 객체를 생성하는 코드

Runnable runnable = new Runnable(){
 public void run(){........}             //익명 구현 객체
}


익명 구현 객체를 람다식으로 표현한 코드
Runnable runnable = (타입 매개변수) -> {실행문.......};       <- 람다식

-> 기호는 타입 매개 변수를 이용해서 중괄호{실행문}블록을
   실행한다는 뜻으로 이해하면 된다.
   만약 실행문에 return문만 있으면 중괄호는 생략할 수 있다.
   ex) (x,y) -> x + y




-익명 구현 객체-


-말 그대로 이름이 없는 객체.
-단독 생성이 불가능 해서 클래스를 상속하거나 인터페이스를 구현해야만 생성이 가능하다.
-익명 구현 객체를 사용하면 인터페이스를 구현한 클래스를 따로 만들 필요가 없게 되어
 더 간결하게 인터페이스를 구현할 수 있다.

   ㄴ형식 : new 클래스명() {내용} 이렇게 사용한다.




-타겟 타입-


인터페이스는 직접 객체화할 수 없기 때문에 구현 클래스가 필요한데, 람다식은
구현 클래스를 생성하고 객체화 한다.
람다식은 대입될 인터페이스의 종류에 따라 작성 방법이 달라지기 때문에 람다식이 대입될 인터페이스를
람다식의 타겟 타입이라고 한다.




-함수적 인터페이스-


람다식은 하나의 메소드만 정의하기때문에 두개 이상의 추상 메소드가 선언된 인터페이스는
람다식을 사용해 구현 객체를 생성할 수 없다.
하나의 추상 메소드가 선언된 인터페이스만이 람다식의 타겟 타입이 될 수 있는데, 이러한 인터페이스를
함수적 인터페이스라고 한다.
함수적 인터페이스를 작성할때 컴파일러가 두 개 이상의 추상 메소드가 선언되지 않도록 체킹해주는
기능이 있는데 인터페이스 선언시 @Functionallnterface 어노테이션을 붙이면 된다.
어노테이션은 두 개 이상의 추상 메소드가 선언되면 컴파일 오류를 발생시킨다.





-예제 및 출력 결과-


1
2
3
4
5
6
7
8
package com.hs.chap14;
 
public interface MyFunctionalInterface {
    
    public void method();
 
}
 
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.hs.chap14;
 
public class MyFunctionalInterfaceExample {
 
    public static void main(String[] args) {
        MyFunctionalInterface fi;
 
        fi = () -> {
            String str = "method call1";
            System.out.println(str);
            //람다식으로 fi필드에 저장될 method메소드의 실행문을 적어준다.
        };
        fi.method();  //fi의 메소드를 호출하면 위에서 람다식으로 작성한 실행문이 출력된다.
 
        fi = () -> {
            System.out.println("method call2");
        };
        fi.method();
 
        fi = () -> System.out.println("method call3");
        fi.method();
    }
}
 
cs






-예제 및 출력결과-


(매개변수가 있는 추상메소드 정의)


1
2
3
4
5
6
7
8
package com.hs.chap14;
 
public interface MyFunctionalInterface {
    //매개 변수가 있는  추상 메소드 정의
    public void method(int a);
 
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.hs.chap14;
 
public class MyFunctionalInterfaceExample {
    // 추상메소드 매개변수에 들어갈 값을 설정.
    private static int a = 5;
 
    public static void main(String[] args) {
        MyFunctionalInterface fi;
        // 람다식으로 fi필드에 저장될 method메소드의 실행문과 매개변수를 적어준다.
        fi = (a) -> {
            String str = "매개변수가 들어간 람다식 실행";
            System.out.println(str);
            System.out.println("나의 이름은" + a + "글자 입니다.");
 
        };
        fi.method(a); // fi의 메소드를 호출하면 위에서 람다식으로 작성한 실행문이 출력된다.
 
    }
}
 
cs






-예제 및 출력결과-


(매개변수와 리턴값이 있는 추상메소드 정의 및 호출)


1
2
3
4
5
6
7
8
package com.hs.chap14;
 
public interface MyFunctionalInterface {
    //두개의 매개 변수가 있는  추상 메소드 정의, 리턴값 없음
    public int method(int a, int b);
 
}
 
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.hs.chap14;
 
public class MyFunctionalInterfaceExample {
 
    public static void main(String[] args) {
        MyFunctionalInterface fi;
        // 람다식으로 fi필드에 저장될 method메소드의 매개변수로 a,b를 선언하고, a+b의 값을 리턴해서 fi필드에 저장한다.
        fi = (a, b) -> {
            int result = a + b;
            return result;
        };
        System.out.println(fi.method(5, 10)); // fi의 method에 5,10을 주고 출력하면 method가 호출되서 두수를 더한값이 출력된다.
 
    }
}
 
cs




-추상 메소드-


매개변수와 리턴값이 없는 메소드




-클래스 멤버와 로컬변수를 람다식으로 사용-


일반적으로 익명 객체 내부에서 this는 익명 객체의 참조이지만, 람다식에서 this는 내부적으로 생성되는
익명 객체의 참조가 아니라 람다식을 실행한 객체의 참조이다.




-디폴트 메소드-


인터페이스에 신규 메소드를 모든 구현 클래스 수정 없이 추가하고자 할때 사용한다.
인터페이스에 디폴트 메소드를 추가하고 Override하고 싶은 클래스만 구현하여 실행할 수 있다.
디폴트 메소드를 가진 인터페이스를 상속받을 때 추상 메소드로 재선언이 가능하다.




-로컬 변수-


메소드 안에 선언한 변수이고, 매소드의 매개 변수 또는 로컬 변수를 사용하면 이 변수는 final 특성을
가져야 한다. 그렇기 때문에 람다식 내부 또는 외부에서 로컬변수를 변경할 수 없다.

하지만 메소드 블록 내부에서 사용하는 것은 가능하다.


(이유 : 변수의 값이 변하는 것을 원치 않아서 메소드 내부에 변수 선언을 하게 되는데 시스템에서 이러한
 특성때문에 메소드 내부에 선언된 변수는 fianl 타입으로 자동적으로 인식되서 메소드 밖에서 변환
 할수가 없게끔 되는것이다.)




-Consumer 함수적 인터페이스-


리턴값이 없는 accept() 메소드를 가지고 있다.
accept() 메소드는 단지 매개값을 소비하는 역할만 한다. 여기서 소비한다는 말은 사용만 할 뿐 리턴값이
없다는 뜻이다.




-Supplier 함수적 인터페이스-


매개 변수가 없고 리턴값이 있는 getXXX() 메소드를 가지고 있다.
실행 후 호출한 곳으로 데이터를 리턴(공급)하는 역할을 한다.




-Predicate 함수적 인터페이스-


매개 변수와 boolean 리턴값이 있는 testXXXX() 메소드를 가지고 있다.
이 메소드들은 매개값을 조사해서 true 또는 false를 리턴하는 역할을 한다.




-andThen()와 compose()디폴트 메소드-


andThen()와 compose()디폴트 메소드 두개의 함수적 인터페이스를 순차적으로 연결하고, 첫 번째 처리 결과를
두 번째 매개값으로 제공해서 최종 결과값을 얻을때 사용한다.


인터페이스AB = 인터페이스A.andThen(인터페이스B);
최종결과 = 인터페이스AB.method();


andThen() 메소드는 인터페이스 AB의 method()를 호출하면 우선 인터페이스A 부터 처리하고 결과를
인터페이스B의 매개값으로 제공한다. 인터페이스B는 제공받은 매개값을 가지고 처리한 후 최종 결과를 리턴


compose() 메소드는 인터페이스AB의 method()를 호출하면 인터페이스 B부터 처리하고 결과를 인터페이스A의
매개값으로 제공한다. 인터페이스A는 제공받은 매개값을 가지고 처리한 후 최종 결과를 리턴한다.



-Predicate 종류 함수적 인터페이스-


and() 메소드 : 두 Predicate가 모두 true를 리턴하면 최종적으로 true를 리턴하는 Predicate를 생성한다.


or() 메소드 : 두 Predicate 중 하나만 true를 리턴하더라도 최종적으로 true를 리턴하는 Predicate를 생성한다.


negate() 메소드 : 원래 Predicate의 결과가 true이면 false로, false면 true를 리턴하는 새로운 Predicate를 생성한다.


isEqual() 메소드 : test() 매개값인 sourceObject와 isEqual()의 매개값인 targetObject를 Objects 클래스의 equals()의
                      매개값으로 제공하고, equals(sourceObject,targetObject)의 리턴값을 얻어 새로운 Predicate<T>를
                       생성한다.




-예제 및 출력 결과-


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.hs.chap14;
 
import java.util.function.Predicate;
 
public class PredicateIsEqualExample {
 
    public static void main(String[] args) {
        Predicate<String> predicate;
        
        predicate = Predicate.isEqual(null);
        System.out.println("null과 null은"+predicate.test(null));
        
        predicate = Predicate.isEqual("Java");
        System.out.println("Java와 null은"+predicate.test(null));
 
    }
}
 
cs



 

 


 

 

-정적 메소드와 인스턴스 메소드 참조-

 

정적 메소드를 참조할 경우에는 클래스 이름 뒤에 : : 기호를 붙이고 정적 메소드 이름을 기입한다.

 

클래스 : : 메소드

 

인스턴스 메소드일 경우에는 먼저 객체를 생성한 다음 참조 변수 뒤에 : : 기호를 붙이고 인스턴스 메소드 이름을 기술하면 된다.

 

참조변수 : : 메소드

 

 

 

-예제 및 출력 결과-

1
2
3
4
5
6
7
8
9
10
11
12
package com.hs.chap14;
 
public class Calculator {
    public static int staticMethod(int x, int y) {
        return x + y;
    }
 
    public int instanceMethod(int x, int y) {
        return x + y;
    }
}
 
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.hs.chap14;
 
import java.util.function.IntBinaryOperator;
 
public class MethodReferencesExample {
    public static void main(String[] args) {
        IntBinaryOperator operator;
 
        // 정적 메소드 참조
        operator = (x, y) -> Calculator.staticMethod(x, y); // 람다식 사용
        System.out.println("결과1: " + operator.applyAsInt(12)); // x,y값에 각각 1과 2를 주어서 더한값을 출력함.
 
        operator = Calculator::staticMethod; // staticMethod(정적메소드)를 참조
        System.out.println("결과2: " + operator.applyAsInt(34)); // x,y값에 각각 3과 4를 주어서 더한값을 출력함.
 
        // 인스턴트 메소드 참조
        Calculator obj = new Calculator();
 
        operator = (x, y) -> obj.instanceMethod(x, y); // 람다식 사용
        System.out.println("결과3:" + operator.applyAsInt(56)); // x,y값에 5와 6을 넣어서 더한값 출력
 
        operator = obj::instanceMethod; // instanceMethod(인스턴스 메소드)를 참조
        System.out.println("결과4:" + operator.applyAsInt(78)); // x,y값에 7과 8을 넣어서 더한값 출력
 
        operator = (x, y) -> obj.instanceMethod(x, y); // 람다식 사용
        System.out.println("결과3:" + operator.applyAsInt(56)); // x,y값에 5와 6을 넣어서 더한값 출력
 
    }
}
 
cs




 

 

 

 

 

 

 

 

-중요 예제-

 

http://www.java2s.com/Tutorials/Java/java.util.function/Consumer/index.htm

728x90
반응형
: