6
votes

Puis-je faire cette méthode Java Cueillir () plus sûre?

J'ai écrit cette fonction utilitaire: xxx

J'ai copié l'idée de Underscore.js . Le cas d'utilisation est le suivant: xxx

Mon problème est que si l'appelant obtient le type de type, aucune exception n'est lancée tant que l'appelant a essayé d'obtenir un objet de la liste. Idéalement, j'aimerais jeter un Classcastexception à partir de la méthode PLUCK . Cependant, je ne vois pas un moyen d'accéder au type de la liste sur le temps d'exécution.

Y a-t-il des astuces que je peux utiliser pour vous assurer que l'appelant ne se retrouve pas avec une liste non valide? < / p>


EDIT: Utiliser les commentaires que j'ai obtenus, une implémentation sûre serait: xxx

mais réellement lambdaj semble Pour faire ce que je voulais, alors je suppose que je vais l'utiliser. Merci Mike!

Disclaimer: lambdaj ( @ googlecode | @github ) - Ce projet n'est plus maintenu depuis le Libération de jdk8 ( JSR 335 , Jep 126 ).


3 commentaires

Lambdaj fait cela et bien plus encore, de manière sûre. C'est une de mes bibliothèques préférées.


list.get.get (0) .getclass () pourrait ne pas vous procurer la bonne classe. Si list.get.get (0) est null qu'il va crancer. En outre, les éléments ultérieurs de la liste peuvent ne pas être des instances de list.get.get (0) s classe


Et pour cueillir également des champs de classe privée, vous voudrez peut-être faire ceci: champ f = listtype.getdeclaredfield (Nom de terrain); f.Setaballest (vrai); au lieu de faire champ f = listtype.getfield (nom de terrain);


8 Réponses :


1
votes

Qu'entendez-vous par liste non valide? Si vous voulez dire qu'ils essaient de le jeter à quelque chose, il ne réussit pas alors à changer la déclaration à Public Static Liste Cublication (nom de champ de chaîne, liste Liste) .

Je suis confondu par le Cependant, je ne vois pas un moyen d'accéder au type de liste au moment de l'exécution. Commentaire. Cependant, si je vous comprends correctement, il n'y a pas de "type" au moment de l'exécution car les génériques de Java sont mis en œuvre par "Erasure". Cela signifie que le compilateur vérifie lors de la compilation qu'il fonctionne, puis le transforme en moulages réguliers comme nous avions avant les génériques. Ceci était nécessaire qu'ils ont ressenti de la compatibilité en arrière et en avant.


0 commentaires

0
votes

Je ne sais pas ce que vous demandez, mais vous pouvez essayer:

Class c = list.get(0).getClass();
if (!c.equals(Person.class))
  throw new ClassCastException();


0 commentaires

0
votes

Vous pouvez lancer la liste sur un java.lang.reflect.paramétratedtype et vérifier que le tableau renvoyé par getactualtypearguments () contient la classe dont vous avez besoin. Autre que cela, vous n'êtes pas de chance.


1 commentaires

Cela ne fonctionnerait que si la liste qu'il a eu était, par exemple, une sous-classe définie comme StringList étendra l'arraylist . Pour une liste, vous obtenez avec New ArrayList () , les informations de type ne sont pas conservées.



2
votes

Pourquoi ne définissez-vous pas la signature comme celle-ci:

public static <T, U> List<T> pluck(String fieldName, Class<T> fieldType, List<U> list);


3 commentaires

"Vous empêchez donc une autre source d'erreur (le client fournissant une liste contenant des objets de types différents)" Il n'empêcherait rien; La façon dont vous l'avez écrite, cela accepterait toute liste.


@newacct Il accepterait simplement des listes qui contiennent des objets d'un type spécifique. Vous ne pouvez donc pas passer une liste contenant différents types d'objets. La signature originale accepterait des listes non génériques, ce qui augmenterait la probabilité d'objets étant transmis en ce qui ne contient pas le champ.


@Newacct Vous pouvez simplement ne pas réussir le type 'List'. Mais vous devriez passer une liste par exemple - ou liste .



1
votes

Vous devez utiliser des génériques pour le paramètre de type et transmettre l'objet de la classe du type de retour: xxx

Généralement, lorsque vous obtenez un avertissement sur une mise en forme dangereuse sur un paramètre de type, Vous devriez voir si vous pouvez le remplacer par un appel à classe.cast


0 commentaires

2
votes

Vous pouvez modifier votre signature en suivant:

public static <T, F> List<F> pluck(String fieldName, Class<F> fieldType, 
                                           List<T> list, Class<T> listType)


0 commentaires

1
votes

Vous pouvez essayer celui donné par Google Collections Bibliothèque au lieu de la maintenance d'une nouvelle: Collections2.Transformez comme celle-ci

Collection<Y> yourCollection...
...
Collection<X> expected = Collections2.transform(yourCollection, new Function<Y, X>() {
  public X apply(Y element) {
    return element.getX();
  }
}


0 commentaires

1
votes

Avec la bibliothèque de collections Guava de Google, vous pouvez utiliser Collections2.Transform () code> .

Utilisation h2> donné une interface / classe, par exemple appelé entité code>, votre classe peut implémenter / étendre ceci. p> xxx pré> xxx pré>

maintenant Vous pouvez récupérer une liste de chacun Entity Code> S IDS. P>

public static <T,F> List<F> pluck(String fieldName, Class<F> fieldType, 
        List<T> list, Class<T> listType) throws NoSuchFieldException,
        IllegalAccessException, IllegalArgumentException {
    Field f = listType.getDeclaredField(fieldName);
    f.setAccessible(true);
    return list.stream().map(e -> {
        try { return fieldType.cast(f.get(e)); } catch (Exception e1) { return null; }
    }).collect(Collectors.toList());
}


0 commentaires