Java8 스트림에서 객체를 수정 / 업데이트 할 수 있습니까? 예를 들어. List<User> users
:
users.stream().forEach(u -> u.setProperty("value"))
답변
예, 스트림 내부의 객체 상태를 수정할 수 있지만 대부분의 경우 스트림 소스 상태를 수정하지 않아야 합니다. 에서 비 간섭 우리가 읽을 수 스트림 패키지 문서의 섹션 :
대부분의 데이터 소스에서 간섭 방지 는 스트림 파이프 라인 실행 중에 데이터 소스가 전혀 수정되지 않도록하는 것을 의미합니다 . 이에 대한 주목할만한 예외는 소스가 동시 수정을 처리하도록 특별히 설계된 동시 컬렉션 인 스트림입니다. 동시 스트림 소스는 특성을
Spliterator
보고하는 소스CONCURRENT
입니다.
그래서 괜찮아
List<User> users = getUsers();
users.stream().forEach(u -> u.setProperty(value));
// ^ ^^^^^^^^^^^^^
그러나 이것은 대부분의 경우에 아닙니다
users.stream().forEach(u -> users.remove(u));
//^^^^^ ^^^^^^^^^^^^
ConcurrentModificationException
NPE와 같은 예상치 못한 예외가 발생할 수 있습니다 .
List<Integer> list = IntStream.range(0, 10).boxed().collect(Collectors.toList());
list.stream()
.filter(i -> i > 5)
.forEach(i -> list.remove(i)); //throws NullPointerException
답변
기능적인 방법은 다음과 같습니다.
import static java.util.stream.Collectors.toList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class PredicateTestRun {
public static void main(String[] args) {
List<String> lines = Arrays.asList("a", "b", "c");
System.out.println(lines); // [a, b, c]
Predicate<? super String> predicate = value -> "b".equals(value);
lines = lines.stream().filter(predicate.negate()).collect(toList());
System.out.println(lines); // [a, c]
}
}
이 솔루션에서 원래 목록은 수정되지 않지만 이전 목록과 동일한 변수에서 액세스 할 수있는 새 목록에 예상 결과를 포함해야합니다.
답변
Pshemo가 답변에서 언급했듯이 스트림 소스에 대한 구조적 수정을 수행하려면 한 가지 해결책은 기본 목록 내의 항목 을 사용하여 Collection
유사한 새 인스턴스를 만드는 것 ArrayList
입니다. 새 목록을 반복하고 기본 목록에서 작업을 수행합니다.
new ArrayList<>(users).stream().forEach(u -> users.remove(u));
답변
ConcurrentModificationException을 제거 하려면 CopyOnWriteArrayList를 사용하십시오.
답변
대신에 이상한 물건을 만드는, 당신은 할 수있는 filter()
한 후 map()
당신의 결과.
이것은 훨씬 더 읽기 쉽고 확실합니다. 스트림은 단 하나의 루프로 만들 것입니다.
답변
예, 다음과 같이 경우에 따라 목록의 개체 값을 수정하거나 업데이트 할 수 있습니다.
users.stream().forEach(u -> u.setProperty("some_value"))
그러나 위의 문은 소스 개체를 업데이트합니다. 대부분의 경우 허용되지 않을 수 있습니다.
다행히 다음과 같은 다른 방법이 있습니다.
List<Users> updatedUsers = users.stream().map(u -> u.setProperty("some_value")).collect(Collectors.toList());
이전 목록을 방해하지 않고 업데이트 된 목록을 반환합니다.
답변
이전에 언급했듯이 원래 목록은 수정할 수 없지만 항목을 새 목록으로 스트리밍, 수정 및 수집 할 수 있습니다. 다음은 문자열 요소를 수정하는 방법에 대한 간단한 예입니다.
public class StreamTest {
@Test
public void replaceInsideStream() {
List<String> list = Arrays.asList("test1", "test2_attr", "test3");
List<String> output = list.stream().map(value -> value.replace("_attr", "")).collect(Collectors.toList());
System.out.println("Output: " + output); // Output: [test1, test2, test3]
}
}
