2014-05-25 17 views
9

Powiedzmy, że mam listę Integer i używam metody Java 8 forEach na liście, aby podwoić jej wartości. Say mam następujący kod:forEach nie modyfikuj kolekcji java (8)

List<Integer> l = Arrays.asList(2,3,6,1,9); 
l.forEach(p->p*=2); 

Jako metody foreach podjęcia konsumentów i wzywa go zaakceptować Methos. Wydrukuję listę po uruchomieniu powyższego kodu, a oryginalna lista nie zmienia się.

O ile mi zrozumieć Stream nie zmienia źródło, ale tutaj po prostu zadzwonić przyjąć metodę na każdym elemencie ...

Thank u w advace

Odpowiedz

13

Powodem że forEach nie mutują listę sprowadza się do specyfikacji:

Javadoc dla forEach mówi:

default void forEach(Consumer<? super T> action)

..... domyślnej wdrożenie zachowuje się tak, jakby:

 for (T t : this) 
     action.accept(t); 

Jak widać:

  • action jest Consumer; tj. nie generuje wartości.
  • Semantyka nie pozwala na aktualizację kolekcji this.
+0

Dziękuję za odpowiedź. Ale jeśli T jest jakimś obiektem odniesienia i zmieniam jego zawartość w pętli forEach, powinienem zobaczyć jej nową zawartość. – user1409534

+2

Nie, to nieprawda z lambdami lub bez nich i nigdy nie było. –

+0

@ user1409534 - Można zmienić zawartość obiektu, do którego odwołuje się obiekt, ale nie aktualizuje listy. Aby zaktualizować listę (w sposób, w jaki próbujesz to zrobić), musisz zamienić odniesienie do obiektu na liście na inny. Nie możesz tego zrobić za pomocą 'forEach()'. I oczywiście lambda nie będzie/nie może tego zrobić. –

6

spróbuje użyć map insted forEach zmieniać oryginalny List.

List<Integer> list = Arrays.asList(2,3,6,1,9); 
list=list.stream().map(p -> p * 2).collect(Collectors.toList()); 
System.out.println(list); 
+8

To tworzy nową listę, to nie robi zmodyfikuj istniejącą listę. To chyba lepiej w ten sposób, ale nadal należy pamiętać o rozróżnieniu. –

+0

Dziękuję za odpowiedź. Mam świadomość korzystania z mapy, aby uzyskać nową metodę zbierania i mapowania strumienia. Nie rozumiem, dlaczego wszelka metoda zbierania nie zmienia elementu, jeśli jego jedyne powołanie akceptuje metodę danej lambda? – user1409534

18

Sposób forEach tylko iteracji elementów listy bez ich zmiany, Jeśli chcesz zmienić elementy, można użyć metody replaceAll:

List<Integer> l = Arrays.asList(2,3,6,1,9); 
l.replaceAll(p->p*2);