java17 을 사용하고 sonarlint 로 체크를 해보니 "Stream.toList()" method should be used instead of "collectors" when unmodifiable list needed
로 collect(Collectors.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 는 수정이 가능하다.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
에러를 던진다.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와 수정가능한 취약점을 보완 할 수 있을 거 같다.