Back-End/Spring

Stream을 List로 변환하는 2가지의 방법(Collectors.toList(), Stream.toList())

쩡류 2023. 4. 18. 06:46
728x90

개요

 

사이드 프로젝트에서, 작성한 글에 대한 이미지 업로드 로직에서 이슈가 터지게 되었다.

 

사진 업로드 기능은 이미지를 업로드 창에 올리거나, 기존의 것을 삭제하거나, 업로드 창에 올린 것을 다시 삭제하는 등

 

다양한 경우의 수가 있어서 이를 잘 고려해서 설계해야한다.

 

우리는 2개의 배열을 두어 (업로드 할 이미지, 삭제 될 이미지) 서버로 전달받도록 하였고, 삭제할 이미지는

 

해당 포스트의 기존에 존재하던 이미지인 경우만 삭제하도록 구현하였다.

 

 

문제점

 

문제는 해당 메서드에서 발생했다.

 

해당 메서드는 List를 받아 element 1개를 제외한 List를 만들어 반환 해 주는 메서드인데

 

기존에는 주석처리 된 부분으로 코드 로직을 진행하였다. 

 

하지만 java16 부터 등장한 toList() 메서드는 해당 메서드의 리턴 리스트 자료형이 unmodifiable하다고 한다.

 

 

따라서, 이 후 해당 리스트에 add 연산을 하고자 하면 해당 예외가 발생했다.

 

java.lang.UnsupportedOperationException: null
	at java.util.AbstractList.add(AbstractList.java:148) ~[na:1.8.0_201]
	at java.util.AbstractList.add(AbstractList.java:108) ~[na:1.8.0_201]

 

이유는, 우리가 toList() 메서드로 받는 arrayList 클래스는 AbstractList<E> 추상 클래스를 상속받는데,

 

해당 arrayList 클래스가 add 메서드를 override하지 않았기 때문에 추상클래스의 add 메서드가 그대로 호출이 되어 

 

예외를 던지게 된 것이었다.

 

 

 

 

결과적으로, Collectors.toList() 메서드를 통해 modifiable한 arrayList를 사용하였고, 정상적으로 로직이 작동하였다.

 

 

하지만, Java 진영에서 Stream.toList() 를 권고하는 이유

 

 

람다와 스트림을 도입하게 된 java 8 버전부터 stream연산의 결과를 취합하여 리스트로 반환하는 종단연산인 .collect(Collectors.toList()) 를 사용할 수 있었다.

 

하지만 해당 메서드는 리턴되는 List가 수정이 가능(modifiable) 하다는 특징이 있어서, 메서드의 불변성을 지키기 위해 java10 에서 수정불가능한(unmodifiable) List 로 반환되도록 toUnmodifiableList() 가 새롭게 등장했다고 한다. 하지만 toUnmodfiableList() 는 이름이 장황해서, java16 에서는 이를 보완하기 위해 Stream.toList() 가 등장했다고 한다.

 

 

결과적으로 Collectors.toList() 메서드를 사용하긴 했지만, 해당 메서드를 사용하지 않는 방향으로 코드를 리팩토링 해 봐야 겠다.