wake-up-neo.net

Verwenden von Java8-Streams zum Erstellen einer Liste von Objekten aus einem anderen

Ich habe folgenden Java6- und Java8-Code:

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()));
}

Gibt es in Java8 eine Möglichkeit, die vorherige Verwendung von Lambda übersichtlicher zu gestalten?

16
mat_boy

Ein Stream ist an eine bestimmte iterable/Collection gebunden, sodass Sie zwei Kollektionen nicht wirklich parallel "iterieren" können.

Eine Problemumgehung wäre das Erstellen eines Index-Streams, der sich jedoch gegenüber der for-Schleife nicht unbedingt verbessert. Die Stream-Version könnte folgendermaßen aussehen:

List<ObjectType3> lst3 = IntStream.range(0, lst1.size())
         .mapToObj(i -> new ObjectType3(lst1.get(i).getAVal(), lst2.get(i).getAnotherVal()))
         .collect(toList());
27
assylias

Sie können eine Methode erstellen, mit der zwei Sammlungen in eine neue Sammlung umgewandelt werden, z.

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;
}

Der wichtige Teil hier ist, dass es die erhaltenen iteratorA.next() und iteratorB.next() in einem neuen Objekt abbildet.

Es heißt so:

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);

In Ihrem Beispiel wäre das:

List<ObjectType3> lst3 = singleCollectionOf(lst1, lst2, ArrayList::new, ObjectType3::new);

Wo zum Beispiel Pair::new eine Abkürzung für die lamdda (t, u) -> new Pair(t, u) ist. 

5
skiwi

Ich habe keine Möglichkeit gefunden, einen Stream auf einen anderen zu aktualisieren, aber ich habe eine ähnliche Leistung mit einer Map erzielt. :)

    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)));
0
Ryan Griffin