2016-07-11 5 views
7

Я хотел написать чистую функцию с Java 8, которая возьмет коллекцию в качестве аргумента, применит некоторое изменение к каждому объекту этой коллекции и вернет новую коллекцию после обновления. Я хочу следовать принципам FP, поэтому я не хочу обновлять/модифицировать коллекцию, которая была передана в качестве аргумента.Java 8 изменить элементы потока

Есть ли способ сделать это с помощью Stream API, не создавая сначала первую коллекцию (а затем используя forEach или «normal» для цикла)?

объект Пример ниже и позволяет предположить, что я хочу, чтобы добавить текст к одному из свойства объекта:

public class SampleDTO { 
    private String text; 
} 

Так что я хочу сделать что-то подобное ниже, но без изменения коллекции. Предполагая, что «список» - List<SampleDTO>.

list.forEach(s -> { 
    s.setText(s.getText()+"xxx"); 
}); 
+1

Я бы сказал, что это немного противоречит принципу функционального программирования здесь. Идея состоит в том, чтобы не мутировать состояние, а создавать новое состояние как произведение функции. Вот почему вместо изменения исходного списка вы должны использовать функцию «map», предоставляемую API потока Java, для создания нового списка. – christopher

ответ

12

Вы должны иметь некоторый метод/конструктор, который создает копию существующего SampleDTO экземпляра, такие как конструктор копирования.

Тогда вы можете map каждого оригинала SampleDTO экземпляра к новому SampleDTO, например, и collect их в новый List:

List<SampleDTO> output = 
    list.stream() 
     .map(s-> { 
        SampleDTO n = new SampleDTO(s); // create new instance 
        n.setText(n.getText()+"xxx"); // mutate its state 
        return n; // return mutated instance 
       }) 
     .collect(Collectors.toList()); 
2

Чтобы сделать это более изящный способ, которым я хотел бы предложить создать Method с в классе.

public class SampleDTO { 
private String text; 
public String getText() { 
    return text; 
} 

public void setText(String text) { 
    this.text = text; 
} 

public SampleDTO(String text) { 
    this.text = text; 
} 

public SampleDTO getSampleDTO() { 
    this.setText(getText()+"xxx"); 
    return this; 
} 
    } 

и добавить его любит:

List<SampleDTO> output =list.stream().map(SampleDTO::getSampleDTO).collect(Collectors.toList(); 
+0

@FedericoPeraltaSchaffner Спасибо за комментарий и downvote. Я исправил это. теперь он будет компилировать – soorapadman

+0

Я проигнорировал, потому что у вашего ответа было 1 голос, и я хотел продвигать другие ответы, которые были правильными, извините, если это было слишком суровым.Теперь, когда вы исправили его, я не только вернул свой нижний план, но и сохранил его. –

+0

Однако теперь исходный объект модифицирован, и OP не хочет мутировать ни исходный список, ни его элементы. Вы должны подумать о создании копии исходного объекта с измененным текстовым атрибутом. –

1

Streams неизменен, как строки, так что вы не можете получить вокруг необходимости создавать новый поток/список/массив

Это, сказал, что вы можете использовать. Собрать(), чтобы вернуть новое сообщение об изменении коллекции, поэтому

List<Integer> result = inList.stream().map().Collect() 
1

Я думаю, что было бы лучше, особенно если вы выполняете многопоточную работу, поток исходного списка в новый измененный список или что угодно еще.

Новый список или карта или любая другая структура, которую вы желаете, могут быть созданы как часть процесса потоковой передачи.

Когда процесс потоковой передачи завершен, просто замените оригинал новым.

Все это должно происходить в синхронизированном блоке.

Таким образом, вы получаете максимальную производительность и параллелизм для уменьшения или того, что вы делаете, и заканчиваете атомным свопом.

Смежные вопросы