Siempre me he preguntado por qué Java no hace inferencia de tipos dado que el lenguaje es lo que es y su VM es muy madura. Google's Go es un ejemplo de un idioma con excelente inferencia de tipos y reduce la cantidad de tipeo que uno tiene que hacer. ¿Hay alguna razón especial detrás de que esta característica no sea parte de Java?
44
Respuestas:
Técnicamente hablando, Java tiene inferencia de tipos cuando usa genéricos. Con un método genérico como
El compilador analizará y comprenderá que cuando escribes
Se devolverá una cadena para la primera llamada y un número entero para la segunda llamada en función de lo que se ingresó como argumento. Obtendrá la verificación de tiempo de compilación adecuada como resultado. Además, en Java 7, uno puede obtener algunas inferencias de tipo adicionales al instanciar genéricos como este
Java es lo suficientemente amable como para completar los corchetes angulares en blanco para nosotros. Ahora, ¿por qué Java no admite la inferencia de tipos como parte de la asignación de variables? En un momento, hubo una RFE para la inferencia de tipos en declaraciones variables, pero esto se cerró como "No se solucionará" porque
El colaborador que cerró esto también notó que simplemente se siente "poco parecido a Java", con lo que estoy de acuerdo. La verbosidad de Java puede ser tanto una bendición como una maldición, pero hace que el lenguaje sea lo que es.
Por supuesto, ese RFE en particular no fue el final de esa conversación. Durante Java 7, esta característica se consideró nuevamente , y se crearon algunas implementaciones de prueba, incluida una por el propio James Gosling. Una vez más, esta característica finalmente fue derribada.
Con el lanzamiento de Java 8, ahora obtenemos inferencia de tipos como parte de lambdas como tal:
El compilador de Java puede mirar el método
Collections#sort(List<T>, Comparator<? super T>)
y luego la interfazComparator#compare(T o1, T o2)
y determinarlo,first
ysecond
debería serString
así permitiendo que el programador renuncie a tener que replantear el tipo en la expresión lambda.fuente
First, the redundant type serves as valuable documentation - readers do not have to search for the declaration of getMap() to find out what type it returns
- Sí, si es así,HashMap<String, Integer> map = foo.getMap()
estoy de acuerdo - en C # normalmente no usovar
en tales casos, aunque podría. Pero este argumento no retiene el agua si es asíHashMap<String, Integer> map = new HashMap<String, Integer>()
. Esto es una verdadera redundancia y no veo ningún beneficio en tener que escribir el nombre del tipo dos veces. Y cómo me beneficiaría aquí de una verificación cruzada del compilador, no lo entiendo en absoluto.var
en Java.Humans benefit from the redundancy
es la verdadera respuesta a la pregunta actual, porque cada justificación que he leído parece una excusa gratuita, infundada y ridícula de los diseñadores de Java: tanto C # como C ++ tienen la característica, los diseñadores de C # y C ++ no son menos competentes que Java, y todos están felices de usarlo. ¿Qué es lo que hace que los desarrolladores de Java sean diferentes de los desarrolladores de C # o C ++? Es por eso que estoy de acuerdo con @KonradMorawski, "Así es como se hacen las cosas aquí" parece ser nuevamente la verdadera razón detrás de las escenas para eso.Bueno, en primer lugar, la inferencia de tipos no tiene nada que ver con la madurez del tiempo de ejecución, ya sea que el tiempo de ejecución sea una CPU de 30 años o una VM que sea tan nueva que los bits sigan siendo brillantes. Se trata del compilador.
Dicho esto, está permitido para los genéricos, la razón por la cual no está permitido para los tipos no genéricos parece ser debido a la filosofía: no hay nada que impida que los diseñadores lo agreguen.
Actualización: parece que Java 10 lo admite: http://openjdk.java.net/jeps/286
fuente
Hasta donde yo sé, cuando Java se diseñó a principios de los años noventa, la inferencia de tipos no era tan popular entre los lenguajes convencionales (pero ya era un concepto muy conocido, por ejemplo, en ML). Entonces, puedo imaginar que la inferencia de tipos probablemente no fue compatible porque Java estaba dirigido a programadores provenientes de C ++, Pascal u otros lenguajes convencionales que no lo tenían (principio de menor sorpresa).
Además, uno de los principios de diseño de Java es escribir cosas explícitamente para asegurarse de que el programador y el compilador tengan la misma comprensión del código: la duplicación de información reduce las posibilidades de errores. Por supuesto, puede ser una cuestión de gusto si escribir algunos caracteres más vale la seguridad adicional que proporciona, pero esta fue la filosofía de diseño seguida para Java: escribir cosas explícitamente.
No sé si Java obtendrá inferencia de tipos en el futuro, pero en mi opinión, eso sería una gran revolución para el lenguaje (como Glenn Nelson mencionó, se describió como "no parecido a Java") y luego uno podría considerar dejar caer el nombrar Java a favor de un nuevo nombre.
Si desea usar un lenguaje JVM con inferencia de tipos, puede usar Scala.
fuente
Se me ocurren algunas posibles razones. Una es que la escritura explícita es autodocumentada. Java generalmente hace de esto una prioridad sobre la concisión. Otra razón podría ser en casos donde el tipo es algo ambiguo. Como cuando un tipo o cualquier subtipo puede satisfacer una rutina. Digamos que quiere usar una Lista, pero alguien aparece y usa un método exclusivo de ArrayList. El JIT inferiría una ArrayList y continuaría incluso si quisiera un error de compilación.
fuente
Let's say you want to use a List, but someone comes along and uses a method exclusive to ArrayList. The JIT would infer an ArrayList and carry on even if you wanted a compilation error
- No entiendo esto un poco. La inferencia de tipos tiene lugar en el momento de instaurar una variable, no de invocar un método en ella. ¿Podrías mostrar un ejemplo de lo que querías decir?Contradice la recomendación bien establecida de declarar variables utilizando la interfaz más genérica que se ajuste a sus necesidades e inicializarlas con una clase de implementación adecuada, como en
Eficazmente,
no es más que azúcar sintáctica para
Si lo desea, su IDE puede producirlo a partir de la
new ArrayList<String>()
expresión con "un clic" (refactorizar / crear variable local), pero recuerde que contradice la recomendación de "usar interfaces".fuente