[Java] 18. 함수형 인터페이스(java.util.function 패키지)
java.util.function 패키지 내에 일반적으로 많이 쓰이는 메서드를 함수형 인터페이스로 정의헤서 제공해주고 있다.
1. 함수형 인터페이스
함수형 인터페이스 | 메서드 | 설명 |
---|---|---|
Supplier<T> | T get() | 매개변수는 없고, 반환값만 존재 |
Consumer<T> | void accept(T t) | Supplier 와 반대로 매개변수만 있고, 반환값이 없음 |
Function<T,R> | R apply(T t) | 일반적인 함수. 하나의 매개변수를 받아 결과 반환 |
Predicate<T> | boolean test(T t) | 조건식을 표현시 사용, 매개변수는 하나 반환타입은 boolean |
Predicate<String> isStringEmpty = s -> s.length() == 0;
if (isStringEmpty.test(str)) {
//...
}
2. 매개변수가 두 개인 함수형 인터페이스
함수형 인터페이스 | 메서드 | 설명 |
---|---|---|
BiConsumer<T,U> | void accept(T t, U u) | 두 개의 매개변수만 있고 반환값이 없음 |
BiPredicate<T,U> | boolean test(T t, U u) | 조건식을 표현시 사용, 매개변수는 둘, 반환값은 boolean |
BiFunction<T,U,R> | R apply(T t, U u) | 두 개의 매개변수를 받아서 하나의 결과를 반환 |
3. UnaryOperator(단항연산자)/BinaryOperator(이항연산자) 함수형 인터페이스
UnaryOperator 과 BinaryOperator는 매개변수의 타입과 반환타입이 모두 일치하는 함수형 인터페이스이다
함수형 인터페이스 | 메서드 | 설명 |
---|---|---|
UnaryOperator | T apply(T t) | Function 의 자손 |
BinaryOperator | T apply(T t1, T t2) | BiFunction 의 자손 |
4. Predicate 의 결합
Predicate 의 and(), or(), negate()를 사용해서 Predicate들을 하나로 결합하는 형태
Predicate<Integer> p1 = i -> i < 100;
Predicate<Integer> p2 = i -> i < 200;
Predicate<Integer> p3 = i -> i%2 == 0;
Predicate<Integer> notP = p1.negate(); // i >= 100
Predicate<Integer> combA1 = notP.and(p2).or(p3); // 100 <= i && i < 200 || i%2 == 0
Predicate<Integer> combA2 = notP.and(p2.or(p3)); // 100 <= i && (i < 200 || i%2 ==0>)
System.out.println(combA1.test(2)); // true
System.out.println(combA2.test(2)); // false
5. 컬렉션 프레임워크와 함수형 인터페이스
5-1. Collection 인터페이스
메서드 | 설명 |
---|---|
boolean removeif(Predicate<E> filter) | 조건에 맞는 요소를 삭제 |
public class RemoveIfExample {
public static void main(String[] args) {
// 예시로 사용할 리스트 생성
List<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);
numbers.add(5);
System.out.println("Original List: " + numbers);
// 조건에 맞는 요소를 제거하는 removeIf 메서드 사용
numbers.removeIf(n -> n % 2 == 0); // 짝수 제거
System.out.println("List after removeIf: " + numbers);
}
}
Original List: [1, 2, 3, 4, 5]
List after removeIf: [1, 3, 5]
5-2. List 인터페이스
메서드 | 설명 |
---|---|
void replaceAll(UnaryOperator<E> operator) | 모든 요소를 변환하여 대체 |
public class ReplaceAllExample {
public static void main(String[] args) {
// 예시로 사용할 리스트 생성
List<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);
numbers.add(5);
System.out.println("Original List: " + numbers);
// 모든 요소를 제곱하여 대체하는 replaceAll 메서드 사용
numbers.replaceAll(n -> n * n);
System.out.println("List after replaceAll: " + numbers);
}
}
Original List: [1, 2, 3, 4, 5]
List after replaceAll: [1, 4, 9, 16, 25]
5-3. Iterable 인터페이스
메서드 | 설명 |
---|---|
void forEach(Consumer<T> action) | 모든 요소에 작업 action을 수행 |
public class IterableForEachExample {
public static void main(String[] args) {
// 예시로 사용할 리스트 생성
List<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);
numbers.add(5);
// Consumer 인터페이스를 사용하여 3 이상의 요소만 출력
Consumer<Integer> action = num -> {
if (num >= 3) {
System.out.println(num);
}
};
numbers.forEach(action);
}
}
3
4
5
5-4. Map 인터페이스
compute
메서드 | 설명 |
---|---|
V compute(K key, BiFunction<K,V,V> f) | 지정된 키의 값에 작업 f를 수행 |
compute 메서드를 사용하여 맵의 ‘c’ 키의 값을 10배로 변경
public class MapComputeExample {
public static void main(String[] args) {
// 예시로 사용할 맵 생성
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
System.out.println("Original Map: " + map);
// compute 메서드를 사용하여 'c' 키의 값을 변경
BiFunction<String, Integer, Integer> function = (key, value) -> value * 10;
map.compute("c", function);
System.out.println("Updated Map: " + map);
}
}
Original Map: {a=1, b=2, c=3}
Updated Map: {a=1, b=2, c=30}
computeIfAbsent
메서드 | 설명 |
---|---|
V computeIfAbsent(K key, Function<K,V> f) | 키가 없으면 작업 f 수행 후 추가 |
computeIfAbsent 메서드를 사용하여 ‘c’ 키의 값이 없을 때에만 새로운 값 추가
public class MapComputeIfAbsentExample {
public static void main(String[] args) {
// 예시로 사용할 맵 생성
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
System.out.println("Original Map: " + map);
// computeIfAbsent 메서드를 사용하여 'c' 키의 값이 없을 때에만 새로운 값 추가
Function<String, Integer> function = key -> 10; // 키 'c'에 대한 값 10을 추가
map.computeIfAbsent("c", function);
System.out.println("Updated Map: " + map);
}
}
Original Map: {a=1, b=2}
Updated Map: {a=1, b=2, c=10}
computeIfPresent
메서드 | 설명 |
---|---|
V computeIfPresent(K key, V value, BiFunction<V,V,V> f) | 지정된 키가 있을 때 작업 f 수행 |
computeIfPresent 메서드를 사용하여 맵의 ‘c’ 키의 값을 현재 값에 100을 곱하여 업데이트하고 있습니다. 코드 실행 후, ‘c’ 키의 값이 300으로 업데이트되어 출력됩니다.
public class MapComputeIfPresentExample {
public static void main(String[] args) {
// 예시로 사용할 맵 생성
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
System.out.println("Original Map: " + map);
// computeIfPresent 메서드를 사용하여 'c' 키의 값 업데이트
BiFunction<String, Integer, Integer> function = (key, value) -> value * 100; // 현재 값에 100을 곱해 업데이트
map.computeIfPresent("c", function);
System.out.println("Updated Map: " + map);
}
}
Original Map: {a=1, b=2, c=3}
Updated Map: {a=1, b=2, c=300}
merge
메서드 | 설명 |
---|---|
V merge(K key, V value, BiFunction<V,V,V> f) | 모든 요소에 병합작업 f를 수행 |
merge 메서드는 맵에 키와 값 쌍을 추가하거나, 기존 키의 값을 새로운 값으로 업데이트할 때 사용된다.
public class MapMergeExample {
public static void main(String[] args) {
// 예시로 사용할 맵 생성
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
System.out.println("Original Map: " + map);
// merge 메서드를 사용하여 키 'c'와 값 3을 추가
BiFunction<Integer, Integer, Integer> function = (oldValue, newValue) -> oldValue + newValue; // 기존 값과 새로운 값을 더함
map.merge("c", 3, function);
System.out.println("Updated Map: " + map);
}
}
Original Map: {a=1, b=2}
Updated Map: {a=1, b=2, c=3}
forEach
메서드 | 설명 |
---|---|
void forEach(BiConsumer<K,V> action) | 모든 요소에 작업 action을 수행 |
forEach 메서드는 맵의 각 요소에 대해 주어진 동작(BiConsumer)을 수행합니다. 각 항목은 키와 값의 쌍으로 처리됩니다.
public class MapForEachExample {
public static void main(String[] args) {
// 예시로 사용할 맵 생성
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
// forEach 메서드를 사용하여 모든 맵 요소 출력
BiConsumer<String, Integer> action = (key, value) -> System.out.println("Key: " + key + ", Value: " + value);
map.forEach(action);
}
}
Key: a, Value: 1
Key: b, Value: 2
Key: c, Value: 3
replaceAll
메서드 | 설명 |
---|---|
void replaceAll(BiFunction<K,V,V> f) | 모든 요소에 치환작업 f를 수행 |
replaceAll 메서드를 사용하여 맵의 모든 값에 대해 값을 두 배로 바꾸고 있습니다. replaceAll 메서드에는 키와 값을 받아 새로운 값을 계산하는 BiFunction이 전달
public class MapReplaceAllExample {
public static void main(String[] args) {
// 예시로 사용할 맵 생성
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
System.out.println("Original Map: " + map);
// replaceAll 메서드를 사용하여 모든 값 두 배로 변경
BiFunction<String, Integer, Integer> function = (key, value) -> value * 2; // 값을 두 배로 계산
map.replaceAll(function);
System.out.println("Updated Map: " + map);
}
}
Original Map: {a=1, b=2, c=3}
Updated Map: {a=2, b=4, c=6}
[출처]
- 자바의정석 (저자: 남궁성)