web-dev-qa-db-fra.com

Pourquoi Java ne fait-il pas d'inférence de type?

Je me suis toujours demandé pourquoi Java ne fait pas d'inférence de type étant donné que le langage est ce qu'il est et que son VM est très mature. Google's Go en est un exemple) d'un langage avec une excellente inférence de type et cela réduit la quantité de frappe qu'il faut faire. Y a-t-il une raison particulière pour que cette fonctionnalité ne fasse pas partie de Java?

45
cobie

Techniquement parlant, Java a une inférence de type lors de l'utilisation de génériques. Avec un méthode générique comme

public <T> T foo(T t) {
  return t;
}

Le compilateur analysera et comprendra que lorsque vous écrivez

// String
foo("bar");
// Integer
foo(new Integer(42));

Une chaîne va être retournée pour le premier appel et un nombre entier pour le deuxième appel basé sur ce qui a été entré comme argument. Vous obtiendrez la vérification de compilation appropriée en conséquence. De plus, dans Java 7, on peut obtenir une inférence de type supplémentaire lorsque instanciation de génériques comme ceci

Map<String, String> foo = new HashMap<>();

Java est assez aimable pour remplir les parenthèses vierges pour nous. Maintenant, pourquoi Java supporte l'inférence de type dans le cadre de l'affectation des variables? À un moment donné, il y avait un RFE pour l'inférence de type dans les déclarations de variables, mais cela a été fermé comme "Ne résoudra pas" car

Les humains bénéficient de la redondance de la déclaration de type de deux manières. Tout d'abord, le type redondant sert de documentation précieuse - les lecteurs n'ont pas à rechercher la déclaration de getMap () pour savoir de quel type il retourne. Deuxièmement, la redondance permet au programmeur de déclarer le type souhaité, et ainsi de bénéficier d'une vérification croisée effectuée par le compilateur.

Le contributeur qui a clôturé cela a également noté qu'il se sent juste "non-Java-like", avec lequel je suis d'accord. La verbosité de Java peut être à la fois une bénédiction et une malédiction, mais elle fait du langage ce qu'il est.

Bien sûr, cette RFE particulière n'était pas la fin de cette conversation. Pendant Java 7, cette fonctionnalité était encore une fois considérée , avec quelques implémentations de test en cours de création, dont une par James Gosling lui-même. Encore une fois, cette fonctionnalité a finalement été abattue.

Avec la sortie de Java 8, nous obtenons maintenant l'inférence de type en tant que partie de lambdas en tant que telle:

List<String> names = Arrays.asList("Tom", "Dick", "Harry");
Collections.sort(names, (first, second) -> first.compareTo(second));

Le compilateur Java est capable de regarder la méthode Collections#sort(List<T>, Comparator<? super T>) puis l'interface de Comparator#compare(T o1, T o2) et déterminez que first et second doivent être un String permettant ainsi au programmeur de renoncer à devoir reformuler le type dans l'expression lambda.

61
user7007

Eh bien, tout d'abord, l'inférence de type n'a rien à voir avec la maturité du runtime, que ce runtime soit un CPU vieux de 30 ans ou un VM c'est tellement nouveau que les bits sont encore brillants. Tout est à propos du compilateur.

Cela dit, il est autorisé pour les génériques, la raison pour laquelle il n'est pas autorisé pour les types non génériques semble être due à la philosophie - rien n'empêche les concepteurs de l'ajouter.

Mise à jour: ressemble à Java 10 le prend en charge —- http://openjdk.Java.net/jeps/286

16
jmoreno

Pour autant que je sache, quand Java a été conçu au début des années 90, l'inférence de type n'était pas si populaire parmi les langages traditionnels (mais c'était déjà un concept très bien connu, par exemple en ML). Donc, je peux imaginer que l'inférence de type n'était probablement pas prise en charge car Java était destiné aux programmeurs venant de C++, Pascal ou d'autres langages traditionnels qui ne l'avaient pas (principe de la moindre surprise).

De plus, l'un des principes de conception de Java est d'écrire des choses explicitement pour s'assurer que le programmeur et le compilateur ont la même compréhension du code: la duplication des informations réduit les risques d'erreurs. Bien sûr , il peut être une question de goût si la saisie de quelques caractères supplémentaires vaut la sécurité supplémentaire qu'il offre, mais c'était la philosophie de conception suivie pour Java: écrire des choses explicitement.

Je ne sais pas si Java obtiendra une inférence de type dans le futur mais IMO ce serait une grande révolution pour le langage (comme Glenn Nelson l'a mentionné, il a été décrit comme "non-Java-like") ), puis on pourrait également envisager de supprimer le nom Java en faveur d'un nouveau nom.

Si vous souhaitez utiliser un langage JVM avec inférence de type, vous pouvez utiliser Scala.

5
Giorgio

Je peux penser à quelques raisons possibles. La première est que la saisie explicite est auto-documentée. Java en fait généralement une priorité sur la concision. Une autre raison peut être dans les cas où le type est quelque peu ambigu. Comme lorsqu'un type ou n'importe quel sous-type peut satisfaire une routine. Disons que vous voulez utiliser un List, mais quelqu'un arrive et utilise une méthode exclusive à ArrayList. Le JIT déduirait une ArrayList et continuerait même si vous vouliez une erreur de compilation.

2
jiggy

Cela contredit la recommandation bien établie de déclarer les variables à l'aide de l'interface la plus générique qui répondra à vos besoins et de les initialiser avec une classe d'implémentation appropriée, comme dans

Collection<String> names = new ArrayList<>();

Effectivement,

var names = new ArrayList<String>();

n'est rien d'autre que du sucre syntaxique pour

ArrayList<String> names = new ArrayList<String>();

Si vous le souhaitez, votre IDE peut le produire à partir de l'expression new ArrayList<String>() en "un clic" (refactoriser/créer une variable locale), mais rappelez-vous que cela contredit la "utilisation interfaces "recommandation.

0
Ralf Kleberhoff