8
votes

Recueillir le flux dans le même type de collection

Supposons que j'ai une collection de type inconnu. Ce que je veux faire, c'est le diffuser, faites-le des trucs sur le flux et récupérez-le dans le même type de collection que ma collection d'origine. Par exemple: xxx

L'idée de cet exemple de code incomplète est de renvoyer une liste si col est de la liste Classe (ou sous-classe de celui-ci), un SET Si COL est de SET classe, etc ... le nom de la méthode et réel Les opérations sur le flux ici ne sont pas importantes, je leur ai spécifié juste pour illustrer ma question. Alors, est-ce possible?


1 commentaires

Quelles espèces voulez-vous faire sur le ruisseau? Cela signifie-t-il que vous devez avoir un format de flux spécifique?


3 Réponses :


17
votes

Il n'est pas possible sans violer le principe sur lequel le cadre de flux Java a été construit sur. Cela violerait complètement l'idée d'abstraction du flux de sa représentation physique.

La séquence d'opérations de données en vrac va dans un pipeline em>, voir la photo suivante: pipeline: une séquence d'opérations de données en vrac p>

Le flux est similaire à la CAT de Schrödinger - Il n'est pas matérialisé tant que vous appelez l'opération terminale. La manipulation du flux est complètement abstraite et détachée de la source de flux d'origine. P>

pipeline comme une boîte noire p>

Si vous souhaitez travailler si de bas niveau avec votre stockage de données d'origine, ne vous sentez pas honte simplement en évitant les flux. Ils ne sont qu'un outil, pas rien sacré. En introduisant des ruisseaux, les bonnes vieilles collections sont toujours aussi bonnes qu'elles étaient, avec une valeur ajoutée de l'itération interne - la nouvelle iTerEfer.Foreach () méthode. P>


ajouté pour satisfaire votre curiosité :) p>

une solution possible forte> suit. Je n'aime pas moi-même et je n'ai pas pu résoudre tous les problèmes génériques là-bas, mais cela fonctionne avec des limitations em>. P>

L'idée crée un collecteur renvoyant le même type que la collection d'entrée. Cependant, toutes les collections ne fournissent pas de constructeur nullaire (sans paramètres), et sans que ce soit le classe.newinstance () méthode ne fonctionne pas. Il y a aussi le problème de la maladresse des exceptions vérifiées dans l'expression de Lambda. (Il est mentionné dans cette belle réponse ici: https://stackoverflow.com/a/22919112/28866891 ) p> xxx pré>

Comme vous pouvez le constater, cela fonctionne en général, supposé que votre collection d'origine fournit un constructeur nullaire. P>

public void test() {
    final Collection<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

    final Collection<Integer> arrayList = new ArrayList<>(numbers);
    final Collection<Integer> arrayList2 = getBiggerThan(arrayList, 6);
    System.out.println(arrayList2);
    System.out.println(arrayList2.getClass());
    System.out.println();

    final Collection<Integer> set = new HashSet<>(arrayList);
    final Collection<Integer> set2 = getBiggerThan(set, 6);
    System.out.println(set2);
    System.out.println(set2.getClass());
    System.out.println();

    // This does not work as Arrays.asList() is of a type
    // java.util.Arrays$ArrayList which does not provide a nullary constructor
    final Collection<Integer> numbers2 = getBiggerThan(numbers, 6);
}


2 commentaires

Javadoc pour getclass : " le type de résultat réel est classe } est l'effacement" est l'effacement du type statique de l'expression sur laquelle getclass est appelé. ". Son comme vous devez vivre avec cet avertissement.


Et ce comportement a bon sens: getclass renvoie la classe d'exécution et au moment de l'exécution Tous les paramètres de type ont été effacés. Je pense que nous avons découvert l'une des rares utilisations appropriées des types bruts!



3
votes

Il y a deux problèmes ici: (1) le type d'exécution (classe) de l'entrée et son résultat, et (2) le type de temps de compilation de l'entrée et son résultat.

pour (1) pour (1), Peut sembler étrange, mais en général, il n'est pas possible en Java de créer une copie d'une instance d'une classe arbitraire. Utilisation de getclass (). NewInstance () code> pourrait ne pas fonctionner si la classe n'a pas de constructeur de no-arg accessible ou s'il est immuable. L'objet peut ne pas être clonable code> non plus. Ainsi, l'appelant doit adopter un fournisseur responsable de la création d'une instance de la bonne classe de résultat. P>

pour (2), une dose appropriée de génériques peut rendre ce type de sécurité au moment de la compilation. xxx pré>

Notez qu'il est limité de comparable code> sur le paramètre type t code> de sorte que l'appelant soit limité transmettre une collection de choses comparables. Cela nous permet d'utiliser comparèteo code> pour comparer les valeurs. Nous utilisons également la méthode Collecteurs.tocollection.tocollection.tocollection et transmettez le fournisseur Obtenez la méthode CODE> à celui-ci. P>

Exemples d'utilisation: P>

List<Integer> input1 = Arrays.asList(1, 4, 9, 13, 14, 22);
List<Integer> filtered1 = getBigger(input1, 10, ArrayList::new);

Set<String> input2 = new HashSet<>();
input2.add("foo");
input2.add("bar");
input2.add("baz");
input2.add("qux");
Set<String> filtered2 = getBigger(input2, "c", HashSet::new);


0 commentaires

0
votes

Étant donné que le type de sous-jacent réel n'est connu que la callee de votre méthode, il devrait être de sa responsabilité de collecter à la collection du tout type qu'ils veulent (par exemple en utilisant < Code> Collecteurs.Tocollection (CustomCollectionType :: Nouveau); ). Donc, votre méthode devrait renvoyer flux . Il peut prendre collection ou flux en fonction de la commodité.


0 commentaires