Stream을 List로 변환하는 다양한 방법과 차이(Collectors.toList() vs Stream.toList())

Sera Lee·2022년 3월 16일
3

java

목록 보기
1/1

개요

java17 을 사용하고 sonarlint 로 체크를 해보니 "Stream.toList()" method should be used instead of "collectors" when unmodifiable list neededcollect(Collectors.toList())Stream.toList() 로 변경하는 것을 권고 했다. 왜 그런 것일까?

Stream.toList() 로 권고하는 이유

java8에서 .collect(Collectors.toList()) 를 사용할 수 있는데, 문제는 리턴되는 List가 수정이 가능하기 때문에 java10 에서 수정불가능한(unmodifiable) List 로 반환되도록 toUnmodifiableList() 가 새롭게 등장했다고 한다. 하지만 toUnmodfiableList() 는 이름이 장황해서, java16 에서는 이를 보완하기 위해 Stream.toList() 가 등장했다고 한다.

테스트하기

테스트코드

	@DisplayName("Collectors.toList() modify 가능 테스트")
    @Test
    public void collectorsToList() {
        List<String> modifiable = Stream.of("foo", "bar")
            .collect(Collectors.toList());
        modifiable.add("new");
        assertEquals(3, modifiable.size());
    }

    @DisplayName("Collectors.toUnmodifiableList() modify 불가능 테스트")
    @Test
    public void collectorsToUnmodifiableList() {
        List<String> unmodifiable = Stream.of("foo", "bar")
            .collect(Collectors.toUnmodifiableList());
        assertThrows(UnsupportedOperationException.class,
            () -> unmodifiable.add("new"));
    }

    @DisplayName("Stream.toList() modify 불가능 테스트")
    @Test
    public void streamToList() {
        List<String> unmodifiable = Stream.of("foo", "bar").toList();
//        java.lang.UnsupportedOperationException
//        at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:142)
//        at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.add(ImmutableCollections.java:147)
        assertThrows(UnsupportedOperationException.class,
            () -> unmodifiable.add("new"));

        List<String> copied = List.copyOf(unmodifiable);
        assertThrows(UnsupportedOperationException.class,
            () -> copied.add("new"));
    }

결과

  • collectorsToList() 함수를 보면 .collect(Collectors.toList())에 “new” 를 List에 추가할 수 있으므로, 리턴되는 List 는 수정이 가능하다.
  • 수정이 불가능한 List에 수정을 하려고 하면 UnsupportedOperationException.class 를 던지는데, 상세 로그는 다음과 같다.

    java.lang.UnsupportedOperationException
    at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:142)
    at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.add(ImmutableCollections.java:147)

  • collectorsToUnmodifiableList() 에서는 .collect(Collectors.toUnmodifiableList()) 를 사용하여 반환된 List 에 새로운 item을 추가하면 UnsupportedOperationException.class 에러를 던진다.
  • Stream.of("foo", "bar").toList() 에서는 반환된 List 에 새로운 item을 추가하면 UnsupportedOperationException.class 에러를 던진다.

Null 허용 여부

  • .collect(Collectors.toList()), .collect(Collectors.toUnmodifiableList()), Stream.of.toList() 는 수정여부 이외에 Null 허용 여부에 대해 차이가 있다.
    • Collectors.toList() 는 Null을 허용한다.
    • Collectors.toUnmodifiableList() 는 Null을 허용하지 않는다.
    • Stream.toList() 는 Null을 허용한다.
  • Collectors.toUnmodifiableList() 를 사용하면 Null 을 삽입하게 되는 경우, NPE 런타임 에러가 발생하므로, NPE 로부터 안전하지 않다.

💎 결론

java 8 에서는 collect(Collectors.toList()) 를 사용을 할 수 밖에 없지만, List가 변경될 수 있다는 점을 주의해야 할 거 같다. java 버전을 올려 collect(Collectors.toUnmodifiableList()) 를 사용할 수는 있지만 NPE 로부터 안전하지 못한다는 점을 주의해야할 거 같고, Stream.of.toList() 가 지원되는 LTS java17을 사용하여 NPE와 수정가능한 취약점을 보완 할 수 있을 거 같다.

0개의 댓글