Skip to content

Commit 8d71706

Browse files
authored
[docs] week6_13.제네릭_14.람다식
[docs] week6_13.제네릭_14.람다식
2 parents c6a4d69 + 6b27698 commit 8d71706

File tree

1 file changed

+320
-0
lines changed

1 file changed

+320
-0
lines changed

week6/yena.md

+320
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
# 13. 제네릭
2+
3+
## 주요 키워드 및 개념 정리
4+
5+
### 제네릭 사용 이유
6+
7+
#### 컴파일 시 강한 타입 체크를 할 수 있다.
8+
9+
자바 컴파일러는 잘못 사용된 타입 때문에 발생하는 문제점 제거 위해 제네릭 코드에 대해 강한 타입 체크를 한다.
10+
11+
#### 타입 변환(casting)을 제거한다.
12+
13+
비제네릭 코드는 불필요한 타입 변환을 하기 때문에 성능에 악영향을 미친다. 제네릭 타입을 사용하면 저장될 값의 타입을 제한하기 때문에 타입 변환을 할 필요가 없다.
14+
15+
### 제네릭 사용
16+
17+
#### 제네릭 타입
18+
19+
`class<T>, interface<T>`
20+
제네릭 타입은 타입을 파라미터로 가지는 클래스와 인터페이스를 말한다.
21+
22+
#### 제네릭 타입의 구체적인 타입
23+
24+
실제 코드에서 사용하려면 타입 파라미터에 구체적인 타입을 지정해야 한다.
25+
26+
제네릭은 클래스를 설계할 때 구체적인 타입을 명시하지 않고, 타입 파라미터로 대체했다가 실제 클래스가 사용될 때 구체적인 타입을 지정해 타입 변환을 최소화한다.
27+
28+
#### 멀티 타입 파라미터
29+
30+
`class<K,B,...>, interface<K,V,...>`
31+
제네릭 타입은 두 개 이상의 멀티 타입 파라미터를 사용할 수 있다.
32+
33+
#### `<>`연산자
34+
35+
`Product<Tv, String> product = new Product<>();`
36+
타입 파라미터 부분에 `<>`연산자를 사용하면 자바 컴파일러가 타입 파라미터를 유추해 자동으로 설정해준다.
37+
38+
#### 제네릭 메소드
39+
40+
매개 타입과 리턴 타입으로 타입 파라미터를 갖는 메소드를 말한다.
41+
42+
#### 제네릭 메소드 호출
43+
44+
1. 명시적으로 구체적 타입 지정
45+
```java
46+
리턴타입 변수 = <구체적타입> 메소드명(매개값);
47+
```
48+
2. 매개값을 보고 구체적 타입 추정
49+
```java
50+
리턴타입 변수 = 메소드명(매개값);
51+
```
52+
53+
#### 제한된 타입 파라미터 bounded type parameter
54+
55+
`<T extends 최상위타입>`
56+
타입 파라미터에 지정되는 구체적인 타입을 제한하려면 제한된 타입 파라미터를 사용하면 된다.
57+
58+
타입 파라미터 뒤에 `extends` 키워드를 붙이고 상위 타입(클래스, 인터페이스)을 명시하면 된다. (인터페이스여도 `implements` 사용X)
59+
60+
**주의**: 메소드의 중괄호 {} 안에서 타입 파라미터 변수로 사용 가능한 것은 상위 타입의 멤버로 제한된다. (하위 타입에만 있는 멤버는 사용X)
61+
62+
#### 와일드카드 타입
63+
64+
제네릭 타입을 매개값이나 리턴 타입으로 사용할 때 구체적 타입 대신 와일드카드를 세 가지 형태로 사용할 수 있다.
65+
66+
- `<?>`: 타입 파라미터를 대치하는 구체적인 타입으로 모든 클래스, 모든 인터페이스 타입이 올 수 있음.
67+
- `<? extends 상위타입>`: 상위 클래스 제한.
68+
- `<? super 하위타입>`: 하위 클래스 제한.
69+
70+
#### 제네릭 타입의 상속과 구현
71+
72+
제네릭 타입도 부모 클래스가 될 수 있다. 자식 제네릭 타입은 **추가적으로** 타입 파라미터를 가질 수 있다.
73+
74+
제네릭 인터페이스를 구현한 클래스도 제네릭 타입이 된다.
75+
76+
# 14. 람다식
77+
78+
## 주요 키워드 및 개념 정리
79+
80+
### 람다식이란
81+
82+
#### 람다식 Lambda Expressions
83+
84+
람다식은 익명 함수(anonymous function)를 생성하기 위한 식으로 함수지향 언어에 가깝다.
85+
86+
코드가 간결해지고, 컬렉션의 요소를 필터링 하거나 매핑해서 원하는 결과를 쉽게 집계할 수 있다.
87+
88+
#### 람다식의 형태
89+
90+
매개 변수를 가진 코드 블록으로 런타임 시에는 익명 구현 객체를 생성한다.
91+
92+
### 타겟 타입과 함수적 인터페이스
93+
94+
람다식은 단순히 메소드를 선언하는 것이 아니라 **이 메소드를 가지고 있는 객체를 생성**해낸다. (자바는 메소드를 항상 클래스의 구성 멤버로 선언하기 때문)
95+
96+
-> 람다식은 인터페이스 변수에 대입된다.
97+
-> 람다식은 인터페이스의 익명 구현 객체를 생성한다.
98+
=> 람다식은 구현 클래스를 생성하고 **객체화**한다.
99+
100+
#### 람다식의 타겟 타입
101+
102+
람다식이 대입될 인터페이스를 람다식의 타겟 타입(target type)이라 한다.
103+
104+
#### 함수적 인터페이스 functional interface
105+
106+
람다식은 하나의 메소드를 정의한다. 하나의 추상 메소드만 선언된 인터페이스만 람다식의 타겟 타입이 될 수 있다.
107+
108+
이러한 인터페이스를 함수적 인터페이스라고 한다.
109+
110+
#### 함수적 인터페이스 `@FunctionalInterface`
111+
112+
인터페이스 선언 시 `@FunctionalInterface`을 붙이면 두 개 이상의 추상 메소드가 선언되지 않도록 컴파일러가 체킹한다. (선택 사항)
113+
114+
람다식은 타겟 타입인 함수적 인터페이스의 추상 메소드 선언 형태에 따라 작성 방법이 달라진다.
115+
116+
### 클래스 멤버와 로컬 변수 사용
117+
118+
람다식의 실행 블록에 클래스의 멤버 및 로컬 변수를 사용할 수 있다. 클래스 멤버는 제약 사항 없이 사용 가능하고, 로컬 변수는 제약 사항이 따른다.
119+
120+
#### 클래스의 멤버 사용
121+
122+
람다식에서 this는 생성되는 익명 객체의 참조가 아니라 **람다식을 실행한 객체의 참조**이다.
123+
124+
#### 로컬 변수 사용
125+
126+
- 메소드 내 생성된 익명 객체: 실행 끝나도 힙 메모리에 계속 존재 -> 사용O
127+
128+
- 메소드의 매개변수, 로컬변수: 스택메모리에 생성되어 메소드 실행이 끝나면 사라짐 -> 익명 객체에서 사용할 수 X
129+
130+
**=> 익명객체에서 사용된 매개변수, 로컬변수는 final 특성을 가진다. (final 생략가능)**
131+
132+
그래서 매개 변수, 로컬 변수를 람다식에서 읽는 것은 허용되지만 람다식 내부 또는 외부에서 변경할 수 없다.
133+
134+
### 표준 API의 함수적 인터페이스
135+
136+
자바 8부터 자주 사용되는 함수적 인터페이스는 `java.util.function` 표준 API 패키지로 제공한다.
137+
138+
**목적**: 표준 API 패키지의 함수적 인터페이스를 사용해 메소드 또는 생성자의 매개 타입으로 사용. 람다식을 대입할 수 있도록 하기 위해.
139+
140+
#### 표준 API 패키지 함수적 인터페이스 분류
141+
142+
인터페이스에 선언된 추상 메소드의 매개값과 리턴값의 유무에 따라 구분한다.
143+
144+
#### Consumer
145+
146+
- 추상메소드: 매개값은 있고, 리턴값은 없음
147+
- 리턴값이 없는 `accept()` 사용
148+
- 매개값을 소비하는 역할
149+
150+
#### Supplier
151+
152+
- 추상메소드: 매개값은 없고, 리턴값은 있음
153+
- `getXXX()` 사용
154+
- 실행 후 호출한 곳으로 데이터를 리턴(공급)
155+
156+
#### Function
157+
158+
- 추상메소드: 매개값도 있고, 리턴값도 있음
159+
- `apply()` 사용
160+
- 주로 매개값을 리턴값으로 매핑(타입 변환)
161+
162+
#### Operator
163+
164+
- 추상메소드: 매개값도 있고, 리턴값도 있음
165+
- `applyXXX()` 사용
166+
- 주로 매개값을 연산하고 결과를 리턴
167+
168+
#### Predicate
169+
170+
- 추상메소드: 매개값은 있고, 리턴 타입은 boolean
171+
- `testXXX()` 사용
172+
- 매개값을 조사해서 true/false 리턴
173+
174+
#### 표준 API 함수적 인터페이스의 디폴트 및 정적 메소드
175+
176+
디폴트 및 정적 메소드는 추상 메소드가 아니기 때문에 함수적 인터페이스에 선언되어도 함수적 인터페이스의 성질(하나의 추상 메소드, 람다식으로 익명 구현 객체 생성)을 잃지 않는다.
177+
178+
`java.util.function` 패키지의 함수적 인터페이스는 하나 이상의 디폴트 및 정적 메소드를 가진다.
179+
180+
#### andThen()과 compose() 디폴트 메소드
181+
182+
Consumer, Function, Operator 종류의 함수적 인터페이스에 있는 디폴트 메소드이다.
183+
184+
두 개의 함수적 인터페이스를 순차적으로 연결 하고 첫 번째 처리 결과를 두 번째 매개값으로 제공해 최종 결과값을 얻을 때 사용한다.
185+
186+
- `andThen()`: 인터페이스A 처리 -> 결과를 인터페이스 B의 매개값으로 제공 -> 인터페이스B가 매개값으로 처리 후 최종 결과 리턴
187+
- `compose()`: 인터페이스B 처리 -> 결과를 인터페이스 A의 매개값으로 제공 -> 인터페이스A가 처리 후 최종 결과 리턴
188+
189+
```java
190+
//andThen()
191+
인터페이스AB = 인터페이스A.andThen(인터페이스B);
192+
193+
//compose()
194+
인터페이스AB = 인터페이스A.compose(인터페이스B)
195+
196+
//최종결과
197+
최종결과 = 인터페이스AB.method();
198+
```
199+
200+
#### and(), or(), negate() 디폴트 메소드와 isEqual() 정적 메소드
201+
202+
Predicate 종류의 함수적 인터페이스(리턴타입 boolean)는 `and()`, `or()`, `negate()` 디폴트 메소드를 가진다. 각각 논리 연산자인 `&&`, `||`, `!` 와 대응된다.
203+
204+
- `and()`: 두 Predicate가 모두 true를 리턴하면 최종적으로 true 리턴하는 Predicate 생성
205+
- `or()`: 두 Predicate 중 하나만 true를 리턴해도 최종적으로 true 리턴하는 Predicate 생성
206+
- `negate()`: Predicate의 결과의 반대값을 리턴하는 새로운 Predicate 생성
207+
208+
`Predicate<T>` 함수적 인터페이스는 `isEqual()` 정적 메소드를 추가로 제공한다.
209+
210+
- `isEqual()`: `test()` 매개값인 `sourceObject``isEqual()`의 매개값인 `targetObject``java.util.Objects`클래스의 `equals()`의 매개값으로 제공하고, `Objects.equals(sourceObject, targetObject)`의 리턴값을 얻어 새로운 `Predicate<T>`를 생성한다 _(동등비교)_
211+
212+
```java
213+
Predicate<Object> predicate = Predicate.isEqual(targetObject);
214+
boolean result = predicate.test(sourceObject);
215+
//Objects.equals(sourceObject, targetObject) 실행됨
216+
```
217+
218+
#### minBy(), maxBy() 정적 메소드
219+
220+
`BinaryOperator<T>` 함수적 인터페이스는 `minBy()``maxBy()` 정적 메소드를 제공한다. 매개값으로 제공되는 Comparator를 이용해 최대 T와 최소 T를 얻는 `BinaryOperator<T>`를 리턴한다.
221+
222+
- `minBy(Comparator<? super T> comparator)`
223+
- `maxBy(Comparator<? super T> comparator)`
224+
225+
`Comparator<T>` 함수적 인터페이스 내부에는 `compare()` 메소드가 선언되어 있다.(o1,o2 비교: o1이 작으면 음수, 동일하면 0, o1이 크면 양수 리턴)
226+
227+
```java
228+
@FunctionalInterface
229+
public interface Comparator<T> {
230+
public int compare(T o1, T o2);
231+
}
232+
```
233+
234+
### 메소드 참조 Method References
235+
236+
메소드 참조는 메소드를 참조해 매개 변수의 정보 및 리턴 타입을 알아내어, 람다식에서 불필요한 매개 변수를 제거하는 것이 목적이다.
237+
238+
람다식은 기존 메소드를 단순히 호출만 하는 경우가 많다. 이런 경우 메소드 참조를 이용해 깔끔하게 처리할 수 있다.
239+
240+
`IntBinaryOperator operator = Math :: max;`
241+
242+
#### 정적 메소드와 인스턴스 메소드 참조
243+
244+
- **정적 메소드 참조**: 클래스 이름 뒤 `::` 기호 붙이고 정적 메소드 이름 기술
245+
`클래스 :: 메소드`
246+
- **인스턴스 메소드 참조**: 먼저 객체를 생성한 다음 참조 변수 뒤에 `::` 기호 붙이고 인스턴스 메소드 이름 기술
247+
`참조변수 :: 메소드`
248+
249+
#### 매개 변수의 메소드 참조
250+
251+
메소드 참조에서 참조하는 메소드가 람다식에서 제공되는 매개 변수의 멤버일 수도 있다.
252+
253+
이런 경우 메소드 참조로 표현하면 매개변수 a의 이름 뒤에 `::` 기호를 붙이고 메소드 이름을 기술하면 된다.
254+
255+
작성 방법은 정적 메소드 참조와 동일 하지만 다른 코드가 실행된다.
256+
257+
```java
258+
//람다식
259+
(a,b) -> {a.instanceMethod(B);}
260+
261+
//메소드 참조
262+
클래스 :: instanceMethod
263+
```
264+
265+
#### 생성자 참조
266+
267+
단순히 객체를 생성하고 리턴하도록 구성된 람다식은 생성자 참조로 대치할 수 있다.
268+
269+
클래스 이름 뒤에 `::` 기호를 붙이고 new 연산자를 기술하면 된다.
270+
271+
생성자가 오버로딩 되어 여러개가 있을 경우 컴파일러가 맞는 생성자를 찾아 실행한다.
272+
273+
`클래스 :: new`
274+
275+
## 관심 가는 내용
276+
277+
#### 람다식 기본 문법
278+
279+
- `(타입 매개변수, ...) -> { 실행문; ...}`
280+
()는 오른쪽 중괄호 {} 블록을 실행하기 위해 필요한 값을 제공하는 역할. `->`는 매개 변수를 이용해 중괄호를 실행한다는 뜻.
281+
- `(int a) -> {System.out.prinln(a);}`
282+
매개 변수 타입은 런타임 시 대입되는 값 따라 자동으로 인식되기 때문에 보통 매개 변수 타입을 지정X
283+
- `(a) -> {System.out.prinln(a);}`
284+
하나의 매개 변수: 괄호 생략 가능
285+
하나의 실행문: 중괄호 생략 가능
286+
- `int a -> System.out.prinln(a);`
287+
매개 변수가 없다면 빈 괄호 () 반드시 사용.
288+
- `( ) -> {실행문; ...}`
289+
중괄호에서 결과값을 리턴하면 return문으로 결과값 지정 가능
290+
- `(x,y) -> {return x + y;}`
291+
중괄호에 return문만 있으면 보통 아래처럼 생략해 작성
292+
- `x,y -> x + y`
293+
294+
#### 함수적 인터페이스 작성 방법
295+
296+
인터페이스 이름이 `MyFunctionalInterface`일 때.
297+
298+
람다식이 대입된 인터페이스 참조 변수로 메소드를 호출 하면 람다식 중괄호를 실행 시킴.
299+
300+
- 매개 변수와 리턴값이 없는 람다식
301+
작성: `MyFunctionalInterface fi = () -> {...}`
302+
메소드 호출: `fi.method()`
303+
- 매개 변수가 있는 람다식
304+
작성: `MyFunctionalInterface fi = (x) -> {...} 또는 x -> {...}`
305+
메소드 호출: `fi.method(5);`
306+
- 리턴값이 있는 람다식
307+
작성: `MyFunctionalInterface fi = (x,y) -> {...; return 값;}`
308+
메소드 호출: `int result = fi.method(2,5);`
309+
310+
#### 표준 API 함수적 인터페이스들의 메소드들
311+
312+
각 인터페이스(Consumer, Supplier, Function, Operator, Predicate)는 매개변수와 리턴값(타입, 개수 등)에 따라 여러 인터페이스와 추상 메소드를 가진다. _필요에 따라 찾아 사용할 것._
313+
314+
#### 표준 API 함수적 인터페이스 사용 흐름
315+
316+
1. 사용자 메소드 호출(사용)하면서 매개값으로 람다식 사용 -> 람다식은 인터페이스의 익명구현객체 -> 인터페이스의 인스턴스 대입
317+
318+
2. 사용자 메소드 작성 시 매개값으로 표준API의 함수적 인터페이스 사용 -> 1번 메소드 호출 하면서 익명구현객체인 인스턴스 대입
319+
320+
3. 사용자 메소드 내부에서 매개변수(표준 API의 함수적 인터페이스)의 메소드 호출 -> 인터페이스의 구현객체인 람다식의 코드블록에서 재정의한 메소드가 호출됨

0 commit comments

Comments
 (0)