Java 객체지향 프로그래밍
분해(Decomposition)와 추상화(Abstraction)
- 분해
- 큰 문제를 해결하기 위한 기본 패러다임: 분할과 정복
- 간단하고 잘 정의된 방식으로 서로 상호작용하는 작은 프로그램을 만드는 것
- 다음과 같은 방식으로 분리 가능한 하위 문제로 분해
- 각 하위 문제는 동일한 세부 수준에 있음
- 각 하위 문제는 독립적으로 해결할 수 있음
- 하위 문제에 대한 솔루션을 결합하여 원래 문제를 해결할 수 있음
- 추상화
- 고려할 세부 수준을 변경하여 분해를 생산적으로 수행하는 방법
- 문제를 더 간단한 문제로 변환하기 위해 특정 세부 사항을 무시하는데 동의
- 프로그램 설계 프로세스의 전형
- 분해를 위한 구성요소의 좋은 선택
Collection framework에서 함수형 인터페이스를 사용하는 method
interface | method | 설명 |
---|---|---|
Collection | boolean removeIf(Predicate | 조건에 맞는 요소를 삭제 |
List | void replaceAll(UnaryOperator | 모든 요소를 변환하여 대체 |
Iterable | void forEach(Consumer | 모든 요소에 작업 action 수행 |
Map | V compute(K key,BiFunction<K,V,V>f) | 지정된 키의 값에 작업 f를 수행 |
V computeIfAbsent(K key , Function<K,V> f) | 키가 없으면 , 작업 f 수행 후추가 | |
V computeIfPresent(K key , BiFunction<K,V,V>) f | 지정된 키가 있을 때, 작업 f 수행 | |
V merge(K key , BiFunction<V,V,V> f) | 모든 요소에 병합한 f를 수행 | |
void forEach(BiConsumer<K,V> action) | 모든 요소에 작업 action을 수행 | |
void replaceAll(BiFuntion<K,V,V> f) | 모든 요소에 치환작업 f 를 수행 |
Map
- V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public interface Map<K, V> {
default V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue = get(key);
V newValue = remappingFunction.apply(key, oldValue);
if (newValue == null) {
// delete mapping
if (oldValue != null || containsKey(key)) {
// something to remove
remove(key);
return null;
} else {
// nothing to do. Leave things as they were.
return null;
}
} else {
// add or replace old mapping
put(key, newValue);
return newValue;
}
}
}
K가 Null 이 아니고 Function 값이 0이면 remove 하고 0이 아니라면 새로운 값을 put한다.
- V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface Map<K, V> {
default V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
Objects.requireNonNull(mappingFunction);
V v;
if ((v = get(key)) == null) {
V newValue;
if ((newValue = mappingFunction.apply(key)) != null) {
put(key, newValue);
return newValue;
}
}
return v;
}
}
K가 Null 이고 Function 수행 값이 0이 아니면 수행 값을 put 한다.
- default V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface Map<K, V> {
default V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue;
if ((oldValue = get(key)) != null) {
V newValue = remappingFunction.apply(key, oldValue);
if (newValue != null) {
put(key, newValue);
return newValue;
} else {
remove(key);
return null;
}
} else {
return null;
}
}
}
K가 Null 이 아니고 Function 수행 값이 0이 아니면 수행 값을 put 한다.
- default V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface Map<K, V> {
default V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
Objects.requireNonNull(value);
V oldValue = get(key);
V newValue = (oldValue == null) ? value :
remappingFunction.apply(oldValue, value);
if (newValue == null) {
remove(key);
} else {
put(key, newValue);
}
return newValue;
}
}
K가 존재하고 V가 null이 아니면 (oldValue == null) ? value : remappingFunction.apply(oldValue, value);
결과 값을 put한다.
- default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public interface Map<K, V> {
default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
Objects.requireNonNull(function);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch (IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
// ise thrown from function is not a cme.
v = function.apply(k, v);
try {
entry.setValue(v);
} catch (IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
}
}
}
존재하는 모든 K의 V를 Function 의 수행 값을 setValue 한다.
Function을 확장
- UnaryOperator : extends Function <T,T>
1
2
3
4
5
6
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
static <T> UnaryOperator<T> identity() {
return t -> t;
}
}
Type T의 인자 하나를 받고, 동일한 Type T 를 반환하는 인터페이스
- BinaryOperator : extends BiFunction <T,T,T>
1
2
3
4
5
6
7
8
9
10
11
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
Objects.requireNonNull(comparator);
return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
}
public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
Objects.requireNonNull(comparator);
return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
}
}
Type T의 인자 두개를 받고, 동일한 Type T 를 반환하는 인터페이스
Stream
- 스트림은 데이터 소스를 변경하지 않으며 일회용 작업입니다.
- 람다식으로 요소를 처리 함으로써 코드가 간결해지는 장점이 있습니다.
- 내부 반복자를 사용하여 병렬처리가 쉽습니다.
c