모던 자바 인 액션 (세션 8)

kimseungki·2022년 7월 15일
0
post-thumbnail

개요

컬렉션 팩토리 및 리스트와 집합, 맵의 새로운 관용패턴이 어떤게 있는지 정보를 제공해주는 챕터이다.

컬럭센 펙토리를 쓰기 전

// 우리는 기존에 리스트를 이런 형태로 주로 가져왔다. 
List<String> friends = new ArrayList<>();
friends.add("Raphael");
friends.add("Olivia");
friends.add("Thibaut");
// 이상태로 실행하면 오류가 발생한다.
List<String> friends = Arrays.asList("Raphael", "Olivia");
friends.set(0, "Rechard");
friends.add("Thibaut");
Set<String> friends = Stream.of("Raphael", "Olivia","Thibaut")
  .collect(Collector.toSet());

하지만 이렇게 하면, 새로운 요소를 추가할 때 UnsupportedOperationException이 발생한다.
이유는 고정된 크기의 변환할 수 있는 배열로 내부가 구성되어있기 때문이다.
팩토리 메서드 역시 마찬가지로 고정된 크기이고, 더군다나 데이터 변경이 안되 오히려 기능적으로는 안좋다는 단점이 있다.
하지만 그래도 쓰는 이유가 뭘까? 바로 불필요한 객체 할당을 줄여준다

팩토리 메서드 종류

// 리스트 팩토리 메서드
List<String> friends = List.of("Raphael", "Olivia","Thibaut");
// 집합 팩토리 메서드
Set<String> friends = Set.of("Raphael", "Olivia","Thibaut");
// 맵 팩토리 메서드
Map<String, Integer> ageOfFriends = Map.of("Raphael", 30, "Olivia", 25, "Thibaut", 26);

컬렉션의 변경과 추가생성은 안된다.

리스트와 집합 처리

  1. remove if : 프레디케이트를 만족하는 요소를 제거하고 나머지 요소만 저장
  2. removeAll : 리스트에서 이용할 수 있는 기능으로 UnaryOperator 함수를 이용해 요소를 바꾼다.
  3. sort : List 인터페이스에서 제공하는 기능으로 리스트 정렬
// removeif
transactions.removeIf(transaction -> 
  Character.isDigit(transaction.getReferenceCode().charAt(0)));
// removeAll
 referenceCodes.replaceAll(code -> Character.toUpperCase(code.charAt(0)) + code.subString(1));

맵처리

  1. foreach 메서드 : 키와 value를 출력하기 위한 메서드
  2. 정렬 메서드 : value 또는 키를 기준으로 정렬
  3. getOrDefault 메서드 : 키가 존재하지 않을 때 기본값을 넣는 메서드
// foreach
ageOfFrends.forEach((friends, age) -> System.out.println(friend + " is " + age + " years old"));
// sort
favouriteMovies.entrySet().stream()
  .sorted(Entry.ComparingByKey())
  .forEachOrdered(System.out::println);
// getOrDefault(여담 코테볼때 나도 자주쓰는 편이다.)
System.out.println(favorieMovies.getOrDefault("Olivia", "Matrix"));

계산패턴

  1. computeIfAbsent : 제공된 키에 해당하는 값이 없으면(또는 Null) 키를 애용해 값을 계산 후 맵에 추가
  2. computeIfPresent : 제공된 키가 존재하면 새 값을 계산 후 맵에 추가
  3. compute : 제공된 키로 새 값 계산 후 맵에 저장

삭제패턴

  1. 제공 된 키에 해당하는 맵 항목을 제거하는 메서드
    favoriteMovies.remove(key, value);

교체패턴

  1. 맵의 항목을 바꾸는데 사용할 수 있는 두개의 메서드가 맵에 추가
    1-1. replaceAll : 각 항목의 값을 교체, List의 replaceAll과 유사
    1-2. Replace : 키가 존재하면 맵의 값을 바꿈
favoriteMovies.replaceAll((friend, movie) -> movie.toUpperCase());

합침

두 개의 맵을 합칠 때 사용
1. merge : 중복 된 키가 있으면 두 값을 연결

friends.forEach((k, v) -> 
  everyone.merge(k, v, (movie1, movie2) -> movie1 + " & " + movie2));

개선된 ConcurrentHashMap

최신 기술을 반영한 HashMap

리듀스와 검색

foreach : 각 키와 value 쌍에 주어진 액션 실행
reduce : 모든 key value 쌍에 제공된 리듀스 함수 이용해 결과를 합침
search 널이 아닌 값을 반환할 때까지 각 키와 value 쌍에 함수 적용
예시

// 기준값을 1로 세팅 시 공통 스레드 풀을 이용해 병렬성 극대화
// Long.MAX_VALUE를 기준값으로 설정하면 한 개의 스레드 연산 실행
// 맵의 최대값을 찾는 예시코드
Optional<Integer> maxValue = Optional.ofNullable(map.reduceValues(1, Long::max))

계수

ConcurrentHashMap 클래스는 mappingCount 메서드를 제공, int를 반환하는 mappingCount의 장점은 int 범위를 넘어간 이후 상황을 대처할 수 있다는 것이 장점

ConcurrentHashMap<String,Integer> hash = new ConcurrentHashMap<>();
hash.mappingCount();

집합뷰

ConcurrentHashMap 클래스는 집합뷰로 반환하는 keySet 제공

ConcurrentHashMap.KeySetView<String, Integer> keySet = hash.keySet();

후기

자바9에서는 List.of,Map.of 등 컬렉션 팩토리를 쓰면 객체를 생성을 안해도 된다는 장점이 있다는 것을 처음 알았다. 가독성도 높은만큼 작은 데이터를 처리할 때는 가끔 쓰면 좋을 것 같다는 생각이 들었다. 이번 챕터는 새로운것을 깨닫는 느낌보단 이렇게도 쓸 수 있구나 하는 API문서를 한번 훑어본 기분이었다.

profile
seung 기술블로그

0개의 댓글