web-dev-qa-db-fra.com

Java 10: Will Java 7's Diamond Inference fonctionnera-t-il avec une inférence de type locale?)

De JEP 286 , nous voyons que nous pourrons utiliser l'inférence de type local (var) dans JDK 10 (18.3). Le JEP indique que les compilations suivantes sont attendues:

var list = new ArrayList<String>();  // infers ArrayList<String>

Je suis curieux de savoir ce qui se passerait si nous tentions ce qui suit:

var list = new ArrayList<>();

Est-ce que ce que j'ai proposé dans le deuxième extrait sera compilé? Si c'est le cas (ce dont je doute), le ArrayList accepterait-il Object comme type générique?

J'essaierais cela moi-même, mais je n'ai accès à aucune machine sur laquelle je peux installer les premières versions.

Merci!

36
Jacob G.

Oui, var et l'opérateur diamant peuvent être combinés ensemble. Le compilateur déduira le type générique le plus spécifique:

var list = new ArrayList<>(); // Infers ArrayList<Object>
var list = new ArrayList<>(List.of(1, 2, 3)); // Infers ArrayList<Integer>

Et vous pouvez même les combiner avec une classe anonyme:

var list = new ArrayList<>() {};
29
ZhekaKozlov

"Travailler avec" est une question vague, vous aurez donc probablement des réponses vagues.

L'inférence de type n'est pas une lecture mentale; c'est juste la résolution de contraintes. Moins il y a de contraintes de type disponibles, plus vous risquez de rencontrer un échec ou un résultat surprenant (en déduisant un type auquel vous ne vous attendiez pas, comme Object.)

Diamond dit: les types dont j'ai besoin sont probablement déjà présents sur le côté gauche, pourquoi les répéter sur la droite.

L'inférence de type de variable locale dit: les types dont j'ai besoin sont probablement déjà présents sur le côté droit, pourquoi les répéter sur la gauche.

L'invocation de méthode générique dit: les types dont j'ai besoin sont probablement déjà présents dans les arguments, pourquoi les répéter en tant que témoins.

Si suffisamment d'informations sur le type sont disponibles dans le programme sans arguments de type constructeur manifeste ou type cible à gauche, tout ira bien. Par exemple:

List<String> anotherList = ...
var list = new ArrayList<>(anotherList);

Ici, le compilateur est en mesure d'inférer le paramètre type de ArrayList en examinant le type de l'argument au constructeur (celui qui prend Collection<? extends E>). Il en déduit donc T=String sur le RHS, puis est en mesure de déduire ArrayList<String> sur le LHS.

En d'autres termes, le compilateur va faire ce qu'il peut en fonction des informations que vous lui avez fournies. Moins vous lui fournissez d'informations, plus il est probable qu'elles échouent ou ne font pas ce que vous voulez.

Cela dit, je pense que vous avez posé la mauvaise question. La question de savoir combien vous pouvez laisser de côté ne devrait pas être motivée par "combien le compilateur me laissera-t-il de côté", mais "combien de dommages suis-je en train de causer à la lisibilité de mon programme". La lecture de code est plus importante que l'écriture de code. Il est peu probable que laisser de côté tout ce que vous pouvez laisser de côté optimise la lisibilité. Vous devez vous efforcer de laisser in suffisamment pour vous assurer qu'aucun lecteur ne soit confus lorsqu'il est confronté à votre programme.

22
Brian Goetz

Oui, cela se compilerait. La var dans le code

var list = new ArrayList<>();

doit être déduit du type ArrayList<Object> (Je crois qu'on ne peut précisément pas y déterminer le type exact de l'élément à cause de l'effacement) ce qui reviendrait à utiliser un code tel que: -

ArrayList list = new ArrayList<>(); 
// without the type of the element of list specified

list est finalement déduit comme ArrayList<Object>.


De la FAQ sur la liste de diffusion par Brian: -

Que se passe-t-il si nous demandons des déductions des deux côtés?

Si tu le dis:

var x = new ArrayList<>() 

vous demandez alors au compilateur de déduire à la fois l'argument type à List et le type de x.

Mais vous n'avez pas fourni suffisamment d'informations sur le type pour que le compilateur fasse un bon travail.

Dans la plupart des cas, vous obtiendrez une erreur de compilation informative vous indiquant que vous demandez que votre esprit soit lu. Dans certains cas, nous reviendrons à déduire Object, comme nous le faisons actuellement avec:

Object o = new ArrayList<>()  // always inferred ArrayList<Object> here
12
Naman