π [ko] Stream.collect(Collectors.toList()) vs. Stream.toList()
μ‘°μ¬νμ.
Stream.collect(Collectors.toList()) returns a mutable list, while Stream.toList() (introduced in JDK 16) returns an immutable list. Using Stream.toList() without considering its immutability can lead to UnsupportedOperationException.
Stream.collect(Collectors.toList()) μ Stream.toList() λ λ€λ₯΄λ€!
μ΄λλ production μ λ κ±°μ λ‘μ§μμ λ°μν UnsupportedOperationExceptionβ¦
무μμ΄ λ¬Έμ μμκΉμ?
java λ‘ λ°±μλ κ°λ°μ νλ€ λ³΄λ©΄,
κ°μ₯ νν ν¨ν΄ μ€ νλκ°
νΉμ λ°μ΄ν°λ₯Ό μνλ ννλ‘ λ³ννκ±°λ μΆμΆνλ κ²μ λλ€.
μ΄λλ Stream API λ₯Ό μ¬μ©νλ©΄ νΈλ¦¬νκ³ , μΌλ°μ μΌλ‘ μ’μ κ°λ μ±μ μ μ§ν μ μμ΅λλ€.
μλ μ½λλ₯Ό μ΄ν΄λ΄ μλ€.
List<String> imageUrls = articleImageRepository.findByArticle(article)
.stream()
.map(ArticleImage::getImageUrl)
.collect(Collectors.toList());
μ μ½λ μ€λν«μμλ articleImage μν°ν° 리μ€νΈλ₯Ό 쿼리ν΄μ¨ λ€μ, ImageUrl λ§ List
μ¬κΈ°μ μ£Όλͺ©ν΄μΌ ν λΆλΆμ collect(Collectors.toList()
μ
λλ€.
ν΄λΉ λΆλΆμ 컀μλ₯Ό κ°μ Έλ€ λλ©΄ intelliJ μμλ μλμ κ°μ λ©μΈμ§λ₯Ό λμμ€λλ€.
`collect(toList())` can be replaced with 'toList()'
- Replace 'collect(toList())' with 'toList()'?
μ΄ μ μμ 무μ¬μ½ μλ½νλ€κ°λ, μμμΉ λͺ»ν μ μ¬μ μΈ λ²κ·Έλ₯Ό μλΉμ€μ μ¬μ μ μμ΅λλ€.
π₯ Stream.collect(Collectors.toList()) μ Stream.toList() λ λͺ
λ°±νκ² λ€λ₯΄λ€!
μ΄λ»κ² λ€λ₯ΌκΉ?
μ£Όμν μ°¨μ΄μ μ μλμ κ°μ΅λλ€.
- Stream.collect(Collectors.toList()) λ κ°λ³ 리μ€νΈλ₯Ό λ°ννλ€.
- Stream.toList() λ λΆλ³ 리μ€νΈλ₯Ό λ°ννλ€.
jdk 16 λΆν° λμ
λ λ©μλ μΈ Stream.toList()
λ λΆλ³ 리μ€νΈλ₯Ό λ°ννλ©°, μΈλΆμμ μμ μλ μ UnsupportedOperationException
μ΄ ν°μ§λλ€.
List<String> mutableList = Stream.of("a", "b").collect(Collectors.toList());
mutableList.add("c"); // β
κ°λ₯
List<String> immutableList = Stream.of("a", "b").toList();
immutableList.add("c"); // π₯ UnsupportedOperationException λ°μ
νμν ꡬνμ²΄κ° λΆλ³ 리μ€νΈμΈμ§, κ°λ³λ¦¬μ€νΈμΈμ§ μꡬμ¬νμ μ ννκ² νμ νκ³ μ¬μ©νλ κ²μ΄ μ€μν©λλ€.
IntelliJ, SonarQube λ±μμ collect(Collectors.toList())
λ₯Ό Stream.toList()
μΌλ‘ λ³κ²½νλ κ²μ κΆν μ μμ§λ§,
λ λ©μλμ κΈ°λ₯μ μΈ μ°¨μ΄μ μ λͺ νν μΈμ§νμ§ λͺ»ν μ± λ°μλ€μ΄λ©΄
μν©μ λ°λΌ κ½€λ μ¬κ°ν λ²κ·Έκ° λ°μν μλ μκ² μ£ .
λλ€λ¦¬λ λλ€κ²¨ λ³΄κ³ κ±΄λμΌ ν κ² κ°μ΅λλ€.
λ΄λΆ ꡬν μ½λλ₯Ό λ°λΌκ°μ λ λμΌλ‘ κ²μ¦νκΈ°
μκ°μ μΌλ‘ νμ©λλ€λ©΄ λ°λμ λ΄λΆ ꡬν μ½λλ₯Ό νμΈν΄μ, μ€μ€λ‘ λ©λνλ κ²μ΄ κ°μ₯ κΈ°μ΅μ μ€λ λ¨λ κ² κ°μ΅λλ€.
jdk 17 κΈ°μ€μΌλ‘ μ΄ν΄λ³΄κ² μ΅λλ€.
λ¨Όμ Stream.collect(Collectors.toList())
λΆν° λ°λΌκ°λ΄
μλ€.
/**
* Accumulates the elements of this stream into a {@code List}. The elements in
* the list will be in this stream's encounter order, if one exists. The returned List
* is unmodifiable; calls to any mutator method will always cause
* {@code UnsupportedOperationException} to be thrown. There are no
* guarantees on the implementation type or serializability of the returned List.
*
* <p>The returned instance may be <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
* Callers should make no assumptions about the identity of the returned instances.
* Identity-sensitive operations on these instances (reference equality ({@code ==}),
* identity hash code, and synchronization) are unreliable and should be avoided.
*
* <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
*
* @apiNote If more control over the returned object is required, use
* {@link Collectors#toCollection(Supplier)}.
*
* @implSpec The implementation in this interface returns a List produced as if by the following:
* <pre>{@code
* Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray())))
* }</pre>
*
* @implNote Most instances of Stream will override this method and provide an implementation
* that is highly optimized compared to the implementation in this interface.
*
* @return a List containing the stream elements
*
* @since 16
*/
@SuppressWarnings("unchecked")
default List<T> toList() {
return (List<T>) Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray())));
}
/**
* Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
* specified list. Query operations on the returned list "read through" to the
* specified list, and attempts to modify the returned list, whether
* direct or via its iterator, result in an
* {@code UnsupportedOperationException}.<p>
*
* The returned list will be serializable if the specified list
* is serializable. Similarly, the returned list will implement
* {@link RandomAccess} if the specified list does.
*
* @implNote This method may return its argument if the argument is already unmodifiable.
* @param <T> the class of the objects in the list
* @param list the list for which an unmodifiable view is to be returned.
* @return an unmodifiable view of the specified list.
*/
@SuppressWarnings("unchecked")
public static <T> List<T> unmodifiableList(List<? extends T> list) {
if (list.getClass() == UnmodifiableList.class || list.getClass() == UnmodifiableRandomAccessList.class) {
return (List<T>) list;
}
return (list instanceof RandomAccess ?
new UnmodifiableRandomAccessList<>(list) :
new UnmodifiableList<>(list));
}
μ΄λ²μλ collect(Collectors.toList())
λ₯Ό λ΄
μλ€.
/**
* Returns a {@code Collector} that accumulates the input elements into a
* new {@code List}. There are no guarantees on the type, mutability,
* serializability, or thread-safety of the {@code List} returned; if more
* control over the returned {@code List} is required, use {@link #toCollection(Supplier)}.
*
* @param <T> the type of the input elements
* @return a {@code Collector} which collects all the input elements into a
* {@code List}, in encounter order
*/
public static <T>
Collector<T, ?, List<T>> toList() {
return new CollectorImpl<>(ArrayList::new, List::add,
(left, right) -> { left.addAll(right); return left; },
CH_ID);
}
무μμ΄ λ€λ₯Έκ°μ?
toList()
μμ λ°ννλ ꡬν체λ Collectors.UnmodifiableRandomAccessList
, Collectors.UnmodifiableList
μΌλ‘ λΆλ³ 리μ€νΈμ΄μ§λ§
collect(Collectors.toList())
μμ λ°ννλ ꡬν체λ ArrayList
μΌλ‘ κ°λ³ 리μ€νΈμ
λλ€.
λΆλ³ 리μ€νΈμ μμλ₯Ό μμ νλ €κ³ νλ©΄ UnsupportedOperationException
μ΄ λ°μνκ³ ,
ν΄λΉ μμΈλ runtime μ, ν΄λΉ line μ΄ μνλ λμλ§ λ°μνλ―λ‘ μ°ΎκΈ° μ΄λ ΅μ£ .
UnsupportedOperationException
μ΄ triggering λλ μ½λλ UnmodifiableList
λ΄λΆ μ½λλ₯Ό νμΈν΄μ νμ μ μ»μ μ μμ΅λλ€.
public static <T> List<T> unmodifiableList(List<? extends T> list) {
// ... μλ΅ ...
}
/**
* @serial include
*/
static class UnmodifiableList<E> extends UnmodifiableCollection<E>
implements List<E> {
// ... μλ΅ ...
public E set(int index, E element) {
throw new UnsupportedOperationException();
}
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
public E remove(int index) {
throw new UnsupportedOperationException();
}
public boolean addAll(int index, Collection<? extends E> c) {
throw new UnsupportedOperationException();
}
@Override
public void replaceAll(UnaryOperator<E> operator) {
throw new UnsupportedOperationException();
}
@Override
public void sort(Comparator<? super E> c) {
throw new UnsupportedOperationException();
}
// ... μλ΅ ...
public ListIterator<E> listIterator(final int index) {
return new ListIterator<E>() {
// ... μλ΅ ...
public void remove() {
throw new UnsupportedOperationException();
}
public void set(E e) {
throw new UnsupportedOperationException();
}
public void add(E e) {
throw new UnsupportedOperationException();
}
};
// ... μλ΅ ...
}
P.S.
νμ μμ¬ν΄...
Leave a comment