나누고 싶은 개발 이야기

Data Engineer로서 기록하고 공유하고 싶은 기술들. 책과 함께 이야기합니다.

Language/Java

[Java9] Collections, Streams

devidea 2020. 3. 13. 10:29

JEP 269: Convenience Factory Methods for Collections

 

Java 9 이전에 불변 컬렉션을 만들 때 불편함이 있었다. 

Set을 예로 들면, 파라미터로 Set을 받아서 만들어줬다.

public static <T> Set<T> unmodifiableSet(Set<? extends T> s)

 

불변 컬렉션을 만들기 위해서 또 다른 Set을 만들어서 넘겨줘야해서 불필요한 객체 생성이 있었다.

 

Java 9에서는 Set.of, List.of, Map.of 라는 새로운 팩토리 메서드가 추가되어서 담고자 하는 값을 바로 전달해 불변 컬렉션을 만들 수 있다.

다양한 개수의 고정 파라미터/ 가변적 파라미터를 받는 메서드가 제공된다.

 

아래 코드는 간단한 예제이다.

of 메서드로 생성된 컬렉션을 불변 컬렉션이기 때문에 값을 추가했을 때, UnsupportedOperationException 발생하는지 체크했다.

// java 8 unmodifiableSet
Set<String> beforeSet = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("a", "b", "c")));

List<String> list = List.of("one", "two", "three");
Set<String> set = Set.of("one", "two", "three");
Map<String, String> map = Map.of("foo", "one", "bar", "two");

assertThrows(
        UnsupportedOperationException.class,
        () -> list.add("four"),
        "Expected list.add() to throw"
);

 

Stream Improvements

 

1. iterate

기존의 iterate()는 무한히 발생하는 stream을 만들어주기 때문에 큰 문제가 발생했다.

다음 코드와 같이 filter를 사용하면 제한을 둘 수 있으리라 생각할 수 있지만 종료가 되지 않는다.

// before
IntStream
  .iterate(1, i -> i * 2)
  .filter(i -> i < 20)
  .forEach(System.out::println);

Java 9에서는 두번째 파라미터로 Predicate<? super T> hasNext를 두어서 stream이 종료할 수 있는 조건을 넣을 수 있게 했다.

// after
IntStream
        .iterate(1, i -> i < 20, i -> i * 2)
        .forEach(System.out::println);

 

2. takeWhile

stream을 takeWhile의 파라미터로 받는 Predicate 조건에 맞는 요소들만 리턴해 준다.

아래 코드에서는 연속된 숫자를 스트림으로 받아서 3 이하인 값만 리턴하도록 했다.

long count = Stream.of(1, 2, 3, 4, 5, 6).takeWhile(i -> i <= 3).count();
assertEquals(3, count);

 

3. dropWhile

dropWhile은 takeWhile과 반대이다. Predicate 조건에 맞지 않는 요소들만 리턴해 준다.

long count2 = Stream.of(1, 2, 3, 4, 5, 6).dropWhile(i -> i <= 2).count();
assertEquals(4, count2);

 

4. ofNullable

stream에 값을 추가할 때 null 값을 제외하고 싶을 때 사용한다.

ofNullable 메서드는 stream에 추가하려는 값에 null이 있는지 체크하고 제외한다.

HashMap<Integer, String> mapNumber  = new HashMap<>() {{
    put(1, "one");
    put(2, "two");
    put(3, "three");
    put(null, null);
}};
List<Integer> numbers = Arrays.asList(1, 2, 3, null);

List<String> stringNumbers = numbers.stream()
        .flatMap(s -> Stream.ofNullable(mapNumber.get(s)))
        .collect(Collectors.toList());
System.out.println(stringNumbers);

 

관련 문서

반응형