Carte sur une collection générique dans Java 11 [duplicate]

Nov 28 2020

J'ai essayé de trouver un moyen d'écrire une fonction générique - peut-être n'utilisant pas de génériques - pour mapper sur une collection.

Disons que j'ai une fonction A à B, j'aimerais écrire une fonction qui prend a Collection<A>et retourne a Collection<B>. Notez que A et B ne sont pas des génériques, juste un moyen d'exprimer un modèle général.

Ce que j'ai jusqu'à présent, c'est

public static Collection<Point> points2dToPoints(Collection<Point2D> points) {
    return points.stream()
            .map(Utils::point2dToPoint)
            .collect(Collectors.toCollection(() -> points));

}

Cependant, j'obtiens une erreur de type dans le .collect, parce que je veux évidemment que la nouvelle collection soit Collection<Point>mais je ne sais pas comment obtenir un fournisseur pour cela?

Edit: je voudrais pouvoir utiliser cette fonction de manière générique: si je lui passe un Set j'obtiens un Set en retour, mais si je lui passe une List j'obtiens une liste en retour. est-il même possible de faire cela?

Réponses

3 dreamcrash Nov 28 2020 at 03:32

La meilleure option est de ne pas trop compliquer et de faire simplement:

public static Collection<Point> points2dToPoints(Collection<Point2D> points) {
    return points.stream()
            .map(Utils::point2dToPoint)
            .collect(Collectors.toList());
}

renvoyer un implémentation concrète de l'interface Collection( par exemple, Collectors.toList() ) tout en cachant de l'extérieur les détails de l'implémentation, ( c'est-à-dire avoir Collectiondans la signature de la méthode).

Vous pouvez cependant rendre votre méthode plus générique en lui passant - comme Supplier- quelle implémentation concrète de l'interface Collectionvous voulez qu'elle renvoie, à savoir

 public static Collection<Point> points2dToPoints(Collection<Point2D> points, Supplier<Collection<Point>> aNew) {
        return points.stream()
                .map(Utils::point2dToPoint)
                .collect(toCollection(aNew));

De cette façon, vous pouvez passer l' Collectionimplémentation concrète qui sera retournée, par exemple:

points2dToPoints(.., ArrayList::new);
points2dToPoints(.., TreeSet::new);
2 LiveandLetLive Nov 28 2020 at 03:31

Remplacez l'instruction Collectors.toCollection(() -> points)par Collectors.toList().

Démo:

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

Production:

Car [name=Toyota]
Car [name=Ford]
Car [name=Suzuki]