Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

아이템 44. 표준 함수형 인터페이스를 사용하라 - version 1.0 #105

Closed
Irisation23 opened this issue Feb 5, 2023 Discussed in #101 · 0 comments
Closed
Assignees
Labels
7장 람다와 스트림 이펙티브 자바 7장 (람다와 스트림)

Comments

@Irisation23
Copy link
Member

Discussed in https://github.com/orgs/Study-2-Effective-Java/discussions/101

Originally posted by bunsung92 February 3, 2023
📝 구성


0. 들어가기에 앞서 🤔

자바가 람다를 지원하면서 API를 작성하는 모범 사례도 크게 바뀌었다.
즉 상위 클래스의 기본 메서드를 재정의해 원하는 동작을 구현하는 템플릿 메서드 패턴에서 함수 객체를 받는 정적 팩터리나 생성자를 제공하는 방식으로 바뀌게 되었다.
일반화 해보자면 함수 객체를 매개변수로 받는 생성자와 메서드를 더 많이 만들어야 한다는 말이다.
중요한 점은 매개변수의 함수 객체 타입을 올바르게 선택해야 한다.


1. Version1 removeEldestEntry() 구현하기 - Basic

LinkedHashMap을 이용하여 캐시를 구현한다고 생각해보자.

캐시란? 🧐

값비싼 연산 결과 또는 자주 참조되는 데이터를 메모리 안에 두고, 뒤이은 요청이 보다 빨리 처리될 수 있도록 하는 저장소이다.

removeEldestEntry()@Override하면 캐시로 사용할 수 있다.

  • 해당 메서드가 캐시로 이용될 수 있는 이유 Map 객체가 캐시로 사용될 때 이 메서드를 재정의하여, 새로운 엔트리가 추가될 때마다
    가장 오래된 엔트리를 제거하여 Map 객체가 적절한 크기를 유지할 수 있기 때문이다.
@Override
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
    return false;
}

직접 구현해 보자

먼저 MyCache 제네릭 클래스

import java.util.LinkedHashMap;
import java.util.Map.Entry;

public class MyCache<K, V> extends LinkedHashMap<K, V> {

    private final int limitSize;

    public MyCache(int limitSize) {
        this.limitSize = limitSize;
    }

    @Override
    protected boolean removeEldestEntry(Entry<K, V> eldest) {
        return size() > this.limitSize;
    }
}

Main 클래스

public class Main {

    public static void main(String[] args) {
        MyCache<String, Integer> cache = new MyCache<>(3);
        cache.put("1", 1);
        cache.put("2", 2);
        cache.put("3", 3);
        cache.put("4", 4);
        System.out.println(String.join(", ", cache.keySet()));
    }
}

실행 결과는 다음과 같다.
image


2. Version2 removeEldestEntry() 구현하기 - @FunctionalInterface

MyCache2 제네릭 클래스

import java.util.LinkedHashMap;
import java.util.Map.Entry;

public class MyCache2<K, V> extends LinkedHashMap<K, V> {
    private final EldestEntryRemovalFunction<K, V> eldestEntryRemovalFunction;

    public MyCache2(EldestEntryRemovalFunction<K, V> eldestEntryRemovalFunction) {
        this.eldestEntryRemovalFunction = eldestEntryRemovalFunction;
    }

    @Override
    protected boolean removeEldestEntry(Entry<K, V> eldest) {
        return eldestEntryRemovalFunction.remove(this, eldest);
    }
}

EldestEntryRemovalFunction 인터페이스

import java.util.Map;

public interface EldestEntryRemovalFunction<K, V> {
    boolean remove(Map<K, V> map, Map.Entry<K, V> eldest);
}

main 메서드 - 달라진 부분만 기록

MyCache2<String, Integer> cache2 = new MyCache2<>(((map, eldest) -> map.size() > 3));
// 이하 동일

자 이렇게 함수형 인터페이스를 직접 정의해서 사용할 수 있다.
하지만 EldestEntryRemovalFunction<K, V> 인터페이스의 구조는 이미 표준 자바 함수형 인터페이스에서 정의하고 있다.

3. Version3 removeEldestEntry() 구현하기 - 표준 함수형 인터페이스 ✨

MyCache3 제네릭 클래스

public class MyCache3<K, V> extends LinkedHashMap<K, V> {

  private final BiPredicate<Map<K, V>, Map.Entry<K, V>> biPredicate;

  public Cache(BiPredicate<Map<K, V>, Map.Entry<K, V>> biPredicate) {
    this.biPredicate = biPredicate;
  }

  @Override
  protected boolean removeEldestEntry(Entry<K, V> eldest) {
    return biPredicate.test(this, eldest);
  }
}
// 나머지 동일

1.1 표준 함수형 인터페이스의 종류

1.2 표준 함수형 인터페이스의 도입

1.3 표준 함수형 인터페이스 도입의 예외


2. 핵심 정리 📚


3. 회고 🧹

@Irisation23 Irisation23 added the 7장 람다와 스트림 이펙티브 자바 7장 (람다와 스트림) label Feb 5, 2023
@Irisation23 Irisation23 self-assigned this Feb 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
7장 람다와 스트림 이펙티브 자바 7장 (람다와 스트림)
Projects
None yet
Development

No branches or pull requests

1 participant