[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는 매개변수의 타입과 반환타입이 모두 일치하는 함수형 인터페이스이다

함수형 인터페이스메서드설명
UnaryOperatorT apply(T t)Function 의 자손
BinaryOperatorT 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}




[출처]

  • 자바의정석 (저자: 남궁성)