본문 바로가기
코딩

2022.02.24_14일차_람다식

by 흥뷰자 2022. 2. 28.

14일차 학습내용

1. 람다식 
2. 람다식 기본문법
3. 타겟타입과 함수적 인터페이스
4. 클래스 멤버와 로컬 변수 사용  
5. 표준 API의 함수적 인터페이스
6. 메서드 참조  



1. 람다식 화살표 간결 컬렉션요소 중 필터링매핑으로 원하는결과쉽고빠르게


익명함수를 생성하기 위한 식으로 객체지향 언어보다 함수지향언어에 가깝다. (메서드방식으로돌아간다는말)

형태  매개변수가진 코드블럭. 런타임할때 익명객체로 생성되게 만들어져있다. (익명클레스. 앞부분 변수없는형태)



* Runnable 인터페이스(는 추상메서드 딱하나)의 익명 구현하는 객체 생성하는 코드

#2. 바로실행. 익명클래스로 실현
(new Runnable실행부 생략하면 람다식이 됨~)
#1. 기본문법
(앞부분 클래스명을 엎애면 익명클래스가 됨~)

Runnable runnable = new Runnable (){
            @Override
            public void run(){
                     ... 
                     this. ...     //이거까지는최상위객체?ㅡㅡㅡㅡ
            }
}.run(); 





class Test implements Runnable{
           @Override
           public void run(){
                     ...
ㅡㅡㅡㅡㅡㅡㅡ this. ...     //생성된 객체 test을 지칭
            }
}
// 이걸 구현체로
new 객체생성해서 쓰지
Test test = new Test();    // Test타입으로 객체생성

#3. 람다로 표현하면   
Runnable  runnable = () -> { //Runnable타입으로 객체생성
            ...
                     this. ...     //람다를 실행하는 객체=람다식을 담고 있는 클래스 객체
}
 
인터페이스  변수명 =  람다식;

"(매개변수)->{실행코드}"형태로 작성되는데, 마치 함수 정의 형태를 띄고 있지만 / 런타임시 객체생성까지 한번에 하는겁니다.  (인터페이스구현)
 


#1 -> #2 -> #3 코드가 많이 간결해지네



2. 람다식 기본 문법


(타입 매개변수, ...)->{실행문...}

ex) int형 매개변수 a의 값을 출력하는 람다식
(int a)->{System.out.println(a);}

매개변수 타입은 런타임시에 대입되는 값에 따라 자동으로 인식될 수 있기 때문에
람다식에서는 매개변수의 타입을 일반적으로 언급하지 않는다.

(a) -> System.out.println(a)

만약 매개변수가 없다면, 람다식에서 매개변수가 없어지므로 빈 괄호()를
반드시 표기해줘야한다.

() -> {...}

중괄호{} 실행하고, 결과값을 리턴해야한다면 return문으로 결과값을 지정할 수 있다.

(x,y)->{ return x*y;} 

중괄호{} 안에 return문만 있을 경우, 람다식에서는 return문을 사용하지 않고
바로 식만 작성 가능.



3. 타겟 타입과 함수적 인터페이스


그럼 람다를 언제써? 

인터페이스 구현할때~~

 

어떤 인터페이스?

추상메서드를 하나만 갖는 인터페이스 ( 람다식이 대입되는 인터페이스를 람다식의 타겟타입이라고 한다.  )

인터페이스니까 내부 오버라이딩해서 구현부 만들어 쓰는거지

 


1) 함수적 인터페이스 @FunctionalInterface - jvm이 두개인지 아닌지 검사할 수 있게 붙여줘야 (옵션)
모든 인터페이스를 람다식의 타겟타입으로 사용할 수는 없다. 
람다식의 하나의 메서드를 정의를하니까  (함수적 인터페이스. 함수는 아니지만 함수처럼 기능 식 구현)
두 개 이상의 추상메서드가 선언되어있는 인터페이스는 
람다식을 이용해 구현객체를 생성하는 것이 불가능

<10:3 MyFuntionalInterface

2) 매개변수가 없는 람다식 <#1

우리가 만든 인터페이스를 타겟타입으로 갖는 람다식 (런타임시 객체생성됨)
MyFunctionalInterface my = () -> {...}

호출 사용할 때 변수명.메서드명(); 으로 사용
my.method(); // 

이미 인터페이스 안에 구현된 유일의 메서드명을 알아야겠넹.
해당 메서드를 오버로딩해서 사용하면 돼~~ 

람다의 원래 목적이 단발적 함수의 사용(메서드오버라이딩)하면서 바로 객체생성 해서 쓰려는거~

3) 매개변수가 있는 람다식  < #2
//매개변수 이름은 뭐든 상관없는데, 개수 순서 맞춰야 타입도맞고... 

MyFunctionalINterface my = (변수명)->{...}
my.method(값);

4) 매개변수가 있고 리턴값도 있는 람다식 #3

FunctionalInterface my = (변수명,...) ->{... return 값; };  

FunctionalInterface my = (변수명,...) ->{ return 값; }; 

FunctionalInterface my = (변수명,...) -> 값;   // 생략버전

FunctionalInterface my = (변수명,...) ->{ return 메서드(값); }; 

FunctionalInterface my = (변수명,...) -> 메서드(값);  //생략버전

타입 변수 = my.method(값,...);



4. 클래스 멤버와 로컬 변수 사용  


람다식의 실행 블럭에는 클래스의 멤버(변수, 메서드) 및 지역변수를 사용할 수 있다.
클래스의 멤버는 제약사항이 없이 사용가능하지만, 지역변수는 제약사항이 따른다.

1) 클레스 멤버 사용  
제약없이 사용가능하나, this 키워드를 사용할 때는 주의 필요.
일반적으로 익명객체 내부에서 this는 익명객체의 참조이지만,    a.this.z
람다식에서는 this는 내부적으로 생성되는 익명객체를 가르키는 것이 아니라
람다식을 실행한 객체의 참조이다.  

 

람다식 내부에서 this 나를 실행한 객체 일반적으로 this 나 객체 자신
class A{
       int z;
       class B{
              int x;
              void method ( ) {
                      MyInterface my = ( ) -> {
                              z;                              
                              this.z; (X)불가능.
                              a.this.z;
                              x;
                              this.x; 
                              a.this.x; (X) 불가능입니다.









this 레퍼런스
  7일차 this



2) 지역변수 사용
람다식은 주로 메서드 내부에서 작성되기 때문에,
지역 익명구현 객체를 생성시킨다고 볼 수도 있다.
람다식에서 바깥 클래스의 필드나 메서드는 제한없이 사용할 수 있으나,
메서드의 매개변수 또는 지역변수를 사용하면,
이 두 변수는 final특성을 가져야한다.
매개변수 또는 지역변수를 람다식에서 읽는 것은 허용되지만,
람다식 내부 또는 외부에서 변경할 수 없다. (스택이 있는건 안됭게)

 

람다식의 사용할 때,

밖에 있는걸 가져다 쓰는것만 람다식 안에 쓰면 돼 . 딱 그것만 돌아갈 수 있게. / 일반적으로 메서드는 동일 클래스에 있는 변수를 다시 가져와서 값을 변경하는 게 됐는데 말이지.



5. 표준 API의 함수적 인터페이스 

기본 제공되는 인터페이스에 람다식을 적용하는 방법

( 매개변수 ) -> { 던져주는 식 }


//한개의 매서드 있으면 모두 람다식으로 작성할 수 있다.


<util.function <11:24
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/function/package-summary.html

자바 8부터는 자주 사용되는 함수적 인터페이스를 java.util.function패키지로 제공.

[ 크게 5가지로 분류 ]
Consumer 매개값으로 많이 씀
Supplier 리턴값으로 많이씀
Function 매개값 리턴값 둘다 사용함 
Operator 매개값 리턴값 둘다 사용함 주로 매개값 연산하고 결과리턴
Predicate 매개값, 불리안타입으로 리턴

1) Consumer 함수적 인터페이스
accept() 

Consumer<T> void accept(T t)
BiConsumer<T,U>
DoubleConsumer / IntConsumer / LongConsumer : 기본형 받아 소비
ObjDoubleConsumer / ObjIntConsumer / ObjLongConsumer : 객체와 기본형 받아 소비

왜만든거야

2) Supplier 
매개변수 없고 리턴타입만있는 getXXX()메서드만 가지고 있다. 공급해줌.


3) Function   
매개값, 리턴값이 있는 applyXXX() 메서드

Function<T,R>  R aaply(T t) T로받아 R 타입으로 리턴해줌 
BiFunction<T,U,R> R apply(T t, U u) 매매변수 두개 받아 R타입으로 리턴
//기본형->기본형
기본형To기본형Function 이름..
//객체 -> 기본형
To기본형Function 이름..

 ToIntFunction객체를 인트로 던져주는 #3.

4) Operator  <12:50 operator 
매개변수와 리턴값이 있는 applyXXX() 메서드
매개변수 받아 연산 후 동일한 타입으로 리턴값 제공

UnaryOperator<T> T apply(T t)
BiOperator<T> T apply(T t, T t)
DoubleBinaryOperator / DoubleUnaryOperator
IntBinaryOperator / IntUnaryOperator
LingBinaryOperator / LongUnaryOperator


 최대값 최소값


5) Predicate  <1:7
매개변수와 boolean타입 리턴값이 있는 textXXX()메서드. 를 가짐

Predicate<T>  boolean test(T t)
BiPredicate<T, U>  boolean test(T t, U u)
DoublePredicate / IntPredicate / LongPredicate

1:10 PredEx01

6) andThen(), compose() <2:35 
Consumer, Function, Operator 종류의 인터페이스는
andThen(), compose() 디폴트 메서드를 가지고 있다.
두 메서든, 두 개의 함수적 인터페이스를 순차적으로 연결하고, 
첫번째 처리결과를 두 번째 매개값으로 제공해서
최종결과값을 얻을때 사용... 체인역할

#andThen() : A > B // A의 결과를 B의 매개변수로 받아서 처리
인터페이스AB = 인터페이스A.andThen(인터페이스B)
최종결과 = 인터페이스AB.method();

#compose() : B > A // 
인터페이스AB = 인터페이스A.compose() //순서차이. 쓰는건 동일
최종결과 = 인터페이스AB.method();

consumer순차적 연결 ConsumAndThen.java


 function




7) and(), or(), negate() 디폴트 메서드, ieEqual() 정적메서드 <3:0 동적메서드?
&& || ! 논래연산자와 대응되는 메서드
and() : 두개의 Predicate가 모두 true를 리턴하면 최종적으로 true리턴
or() : 둘 중 하나라도 true면 최종적으로 true리턴
negate() : true/ false 반전지켜서 리턴




6. 메서드 참조  <3:17


람다식에서 불필요한 매개변수를 제거하는 것을 목적으로 사용하는 문법

Math.max(10,20); -> 20 리턴해줌(큰수)

IntBinaryOperator op = (a,b) -> { return Math.max(a, b);};
int result = op.apply(10, 20); ==> 20

//원래코드
class Tset implements INtBinaryOperator{
@Override
public int apply(int a, int b){
if(a>b) return a;
else(a<b) return b;
}
}
Test t = new Test();
int result = t.apply(10,20);



IntBinaryOperator op = Math::max;  /// 두개받아서 이렇게 짧게 써줄수도 있다. 

1) 클래스메서드와 인스턴스메서드 참조
클래스::메서드
참조변수::메서드


2) 매개변수의 메서드 참조  

(a,b) -> {a.instanceMetod(b);}; // a의 인스턴스메서드에 b를 던져줌

클래스::instanceMethod

3:51 function써보기 RefEx02

3) 생성자 참조  <3:59 
== 객체 생성을 의미함.

(a,b) -> { return new 클래스(a,b);}

클래스::new 


내가 매번 클래스 내부 메서드명을 지정하지 않고 apply동일하게 할 수 잇당.




'코딩' 카테고리의 다른 글

2022.02.28_16일차_html, 태그별 속성  (0) 2022.03.02
2022.02.25_15일차_스트림  (0) 2022.03.01
2022.02.23_13일차  (0) 2022.02.27
2022.02.22_12일차_컬렉션  (0) 2022.02.26
2022.02.21_11일차_패키지와 API  (0) 2022.02.25

댓글