Использование потоков Java8 для создания списка объектов из другого
У меня есть следующий код Java6 и Java8:
List<ObjectType1> lst1 = // a list of ObjectType1 objects
List<ObjectType2> lst2 = // a list of ObjectType1 objects, same size of lst1
List<ObjectType3> lst3 = new ArrayLis<ObjectType3>(lst1.size());
for(int i=0; i < lst1.size(); i++){
lst3.add(new ObjectType3(lst1.get(i).getAVal(), lst2.get(i).getAnotherVal()));
}
Есть ли какой-либо способ в Java8 для обработки предыдущего в более сжатом виде с помощью Lambda?
Ответы
Ответ 1
Поток привязан к заданной итерируемой/коллекции, поэтому вы не можете "повторять" две коллекции параллельно.
Одним из способов решения проблемы было бы создание потока индексов, но тогда это не обязательно улучшало бы цикл for. Версия потока может выглядеть так:
List<ObjectType3> lst3 = IntStream.range(0, lst1.size())
.mapToObj(i -> new ObjectType3(lst1.get(i).getAVal(), lst2.get(i).getAnotherVal()))
.collect(toList());
Ответ 2
Вы можете создать метод, который преобразует две коллекции в новую коллекцию, например:
public <T, U, R> Collection<R> singleCollectionOf(final Collection<T> collectionA, final Collection<U> collectionB, final Supplier<Collection<R>> supplier, final BiFunction<T, U, R> mapper) {
if (Objects.requireNonNull(collectionA).size() != Objects.requireNonNull(collectionB).size()) {
throw new IllegalArgumentException();
}
Objects.requireNonNull(supplier);
Objects.requireNonNull(mapper);
Iterator<T> iteratorA = collectionA.iterator();
Iterator<U> iteratorB = collectionB.iterator();
Collection<R> returnCollection = supplier.get();
while (iteratorA.hasNext() && iteratorB.hasNext()) {
returnCollection.add(mapper.apply(iteratorA.next(), iteratorB.next()));
}
return returnCollection;
}
Важная часть здесь состоит в том, что он отобразит полученные iteratorA.next()
и iteratorB.next()
в новый объект.
Он вызывается так:
List<Integer> list1 = IntStream.range(0, 10).boxed().collect(Collectors.toList());
List<Integer> list2 = IntStream.range(0, 10).map(n -> n * n + 1).boxed().collect(Collectors.toList());
singleCollectionOf(list1, list2, ArrayList::new, Pair::new).stream().forEach(System.out::println);
В вашем примере это будет:
List<ObjectType3> lst3 = singleCollectionOf(lst1, lst2, ArrayList::new, ObjectType3::new);
Где, например, Pair::new
является сокращением для lamdda (t, u) -> new Pair(t, u)
.
Ответ 3
Я не нашел способ обновить один поток до другого, однако я совершил аналогичный подвиг с помощью Карты.:)
Map<Integer, String> result = new HashMap<>();
for(int index = 100; index > 0; index--){
result.put(index, String.valueOf(index));
}
result.keySet().stream()
.filter(key -> key%3 == 0)
.sorted()
.forEach(key -> result.put(key, "Fizz"));
result.keySet().stream()
.filter(key -> key%5 == 0)
.sorted()
.forEach(key -> result.put(key, "Buzz"));
result.keySet().stream()
.filter(key -> key%3 == 0 && key%5 == 0)
.sorted()
.forEach(key -> result.put(key, "FizzBuzz"));
result.keySet().stream().forEach(key -> System.out.println(result.get(key)));