Mappatura su raccolta generica in Java 11 [duplicato]
Ho cercato di trovare un modo per scrivere una funzione generica, possibilmente non utilizzando generici, per mappare una raccolta.
Diciamo che ho una funzione da A a B, vorrei scrivere una funzione che accetta a Collection<A>e restituisce a Collection<B>. NOTA che A e B non sono generici, ma solo un modo per esprimere uno schema generale.
Quello che ho finora è
public static Collection<Point> points2dToPoints(Collection<Point2D> points) {
return points.stream()
.map(Utils::point2dToPoint)
.collect(Collectors.toCollection(() -> points));
}
Tuttavia, ricevo un errore di tipo in .collect, perché ovviamente voglio che la nuova collezione sia Collection<Point>ma non sono sicuro di come ottenere un fornitore per questo?
Modifica: vorrei poter utilizzare questa funzione in modo generico: se passo un Set ricevo in cambio un Set, ma se lo passo una List ottengo in cambio una lista. è anche possibile farlo?
Risposte
L'opzione migliore è non complicare eccessivamente e semplicemente fare:
public static Collection<Point> points2dToPoints(Collection<Point2D> points) {
return points.stream()
.map(Utils::point2dToPoint)
.collect(Collectors.toList());
}
restituendo un implementazione concreta dell'interfaccia Collection( ad esempio Collectors.toList() ) nascondendo dall'esterno i dettagli di implementazione, ( cioè avendo Collectionnel metodo la firma).
Puoi, tuttavia, rendere il tuo metodo più generico passando ad esso - come Supplier- quale implementazione concreta dell'interfaccia Collectionvuoi che restituisca, ovvero
public static Collection<Point> points2dToPoints(Collection<Point2D> points, Supplier<Collection<Point>> aNew) {
return points.stream()
.map(Utils::point2dToPoint)
.collect(toCollection(aNew));
In questo modo puoi passare l' Collectionimplementazione concreta che ti verrà restituita, ad esempio:
points2dToPoints(.., ArrayList::new);
points2dToPoints(.., TreeSet::new);
Sostituisci la dichiarazione Collectors.toCollection(() -> points)con Collectors.toList().
Demo:
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
class Car {
String name;
public Car(String name) {
this.name = name;
}
@Override
public String toString() {
return "Car [name=" + name + "]";
}
}
class Book {
Car car;
public Book(Car car) {
this.car = car;
}
public Car getCar() {
return car;
}
}
public class Main {
public static void main(String[] args) {
// Test
Collection<Car> list = points2dToPoints(
List.of(new Book(new Car("Toyota")), new Book(new Car("Ford")), new Book(new Car("Suzuki"))));
list.forEach(System.out::println);
}
public static Collection<Car> points2dToPoints(Collection<Book> points) {
return points.stream().map(Book::getCar).collect(Collectors.toList());
}
}
Produzione:
Car [name=Toyota]
Car [name=Ford]
Car [name=Suzuki]