He estado programando durante algunos años y comencé en Java, y en mi tiempo he encontrado muchas fuentes diferentes que afirman que Java es un lenguaje inferior de una manera u otra. Soy consciente de que cada idioma tiene sus fortalezas y debilidades, pero muchas de las cosas que he leído sobre Java parecen estar desactualizadas.
La razón más frecuentemente citada para que Java sea inferior es que es mucho más lenta que otros lenguajes compilados de forma nativa, como C ++, por ejemplo. Muchas personas critican al diseñador de juegos Notch (que desarrolló Minecraft) por usar Java debido a su aparente falta en el departamento de rendimiento. Sé que Java fue mucho más lento en el día, pero ha habido muchas mejoras desde entonces, especialmente la compilación JIT.
Me gustaría obtener algunas opiniones objetivas de Java como lenguaje hoy. Entonces mi pregunta tiene 4 partes.
Actuación.
a. ¿Cómo se compara hoy la velocidad de Java con C ++?
si. ¿Sería posible crear un título AAA moderno usando Java?
C. ¿En qué áreas específicamente Java es más lento que C ++, si es que lo hace? (es decir, números, gráficos o simplemente todo)
¿Se considera Java ahora un lenguaje compilado o un lenguaje interpretado?
¿Cuáles son algunas de las principales deficiencias de Java que se han abordado desde los primeros días?
¿Cuáles son algunas de las principales deficiencias de Java que aún no se han abordado?
Editar:
Solo para fines de aclaración, no estoy haciendo este Java vs C ++, obviamente, en promedio, C ++ será un poco más rápido que Java. Simplemente necesito algo para comparar Java en términos de madurez como lenguaje en este momento. Como c ++ ha existido desde siempre, pensé que sería un buen punto de comparación.
fuente
Respuestas:
Difícil de medir. Vale la pena señalar que una parte importante de la velocidad de una implementación, su asignador de memoria, son algoritmos muy diferentes en Java y C ++. La naturaleza no determinista del recopilador hace que sea extremadamente difícil obtener datos de rendimiento significativos en comparación con la gestión de memoria determinista de C ++, porque nunca puede estar seguro de en qué estado se encuentra el recopilador. Esto significa que es muy difícil escribir un punto de referencia eso podría compararlos significativamente. Algunos patrones de asignación de memoria se ejecutan mucho más rápido con un GC, algunos se ejecutan mucho más rápido con un asignador nativo.
Lo que diría, sin embargo, es que el GC de Java debe ejecutarse rápidamente en cada situación. Sin embargo, un asignador nativo puede cambiarse por uno más apropiado. Recientemente envié una pregunta en SO sobre por qué un C #
Dictionary
podría ejecutarse (0.45 ms en mi máquina) en comparación con un equivalentestd::unordered_map
que se ejecutó el (10 ms en mi máquina). Sin embargo, simplemente cambiando el asignador y el hasher por otros más apropiados, reduje el tiempo de ejecución a 0,34 ms en mi máquina, una trigésima parte del tiempo de ejecución original. Nunca, nunca podría esperar realizar ese tipo de optimización personalizada con Java. Un excelente ejemplo de dónde esto puede hacer una verdadera diferencia es el enhebrado. Las bibliotecas de subprocesos nativas como TBB proporcionan asignadores de almacenamiento en caché de subprocesos que son masivamente más rápidos que los asignadores tradicionales cuando se trata de muchas asignaciones en muchos subprocesos.Ahora, muchas personas hablarán sobre las mejoras de JIT y cómo el JIT tiene más información. Claro, eso es verdad. Pero aún no está ni remotamente cerca de lo que puede obtener un compilador de C ++, porque el compilador tiene, comparativamente, tiempo y espacio infinitos en los que ejecutar, desde la perspectiva del tiempo de ejecución del programa final. Cada ciclo y cada byte que el JIT pasa pensando en cómo optimizar mejor su programa es un ciclo que su programa no está gastando en ejecutar y no puede usar para sus propias necesidades de memoria.
Además, siempre habrá momentos en que las optimizaciones del compilador y JIT no puedan probar ciertas optimizaciones, especialmente en el caso de cosas como el análisis de escape. En C ++, como el valor está en la pila de todos modos , el compilador no necesita realizarlo. Además, hay cosas simples, como la memoria contigua. Si asigna una matriz en C ++, entonces asigna una matriz única y contigua. Si asigna una matriz en Java, entonces no es contigua en absoluto, porque la matriz solo está llena de punteros que podrían apuntar a cualquier parte. Esto no es solo una sobrecarga de memoria y tiempo para las indirecciones dobles, sino también gastos generales de caché. Este tipo de cosas es donde la semántica del lenguaje de Java simplemente impone que debe ser más lento que el código C ++ equivalente.
En última instancia, mi experiencia personal es que Java podría ser aproximadamente la mitad de la velocidad de C ++, en promedio. Sin embargo, no existe una forma realista de hacer una copia de seguridad de las declaraciones de rendimiento sin un conjunto de puntos de referencia extremadamente completo, debido a los algoritmos fundamentalmente diferentes involucrados.
Supongo que te refieres a "juego", aquí, y no a una oportunidad. En primer lugar, tendría que escribir todo desde cero, ya que casi todas las bibliotecas existentes y la infraestructura se dirigen a C ++. Si bien no lo hace imposible per se, ciertamente podría contribuir de manera sólida hacia lo inviable. En segundo lugar, incluso los motores C ++ difícilmente pueden adaptarse a las pequeñas limitaciones de memoria de las consolas existentes, si las JVM existen para esas consolas, y los jugadores de PC esperan un poco más por su memoria. Crear juegos AAA con rendimiento es bastante difícil en C ++, no veo cómo se podría lograr en Java. Nadie ha escrito un juego AAA con un tiempo significativo en un lenguaje no compilado. Más que eso, simplemente sería extremadamente propenso a errores. La destrucción determinista es esencial cuando se trata, por ejemplo, con recursos de GPU, y en Java, usted '
Definitivamente iría por todos lados. La naturaleza de referencia forzada de todos los objetos Java significa que Java tiene muchas más indirectas y referencias que C ++, un ejemplo que di anteriormente con matrices, pero que también se aplica a todos los objetos miembros, por ejemplo. Cuando un compilador de C ++ puede buscar una variable miembro en tiempo constante, un tiempo de ejecución de Java debe seguir otro puntero. Cuantos más accesos haga, más lento será esto, y el JIT no puede hacer nada al respecto.
Donde C ++ puede liberar y reutilizar un trozo de memoria casi al instante, en Java hay que esperar a la colección, y espero que ese trozo no se quede sin caché, e inherentemente requerir más memoria significa menos caché y rendimiento de paginación. Luego mire la semántica para cosas como boxeo y unboxing. En Java, si desea hacer referencia a un int, debe asignarlo dinámicamente. Esa es una pérdida inherente en comparación con la semántica de C ++.
Entonces tienes el problema de los genéricos. En Java, solo puede operar en objetos genéricos a través de la herencia en tiempo de ejecución. En C ++, las plantillas tienen literalmente cero sobrecarga, algo que Java no puede igualar. Esto significa que todo el código genérico en Java es inherentemente más lento que un equivalente genérico en C ++.
Y luego llegas a Comportamiento indefinido. Todos odian cuando su programa exhibe UB, y todos desean que no existiera. Sin embargo, UB fundamentalmente permite optimizaciones que nunca pueden existir en Java. Echa un vistazo a esta publicación que describe las optimizaciones basadas en UB. No definir el comportamiento significa que las implementaciones pueden hacer más optimizaciones y reducir el código requerido para verificar las condiciones que estarían indefinidas en C ++ pero definidas en Java.
Fundamentalmente, la semántica de Java dicta que es un lenguaje más lento que C ++.
Realmente no encaja en ninguno de esos grupos. Diría que gestionado es realmente una categoría separada por sí mismo, aunque diría que definitivamente se parece más a un lenguaje interpretado que a un lenguaje compilado. Más importante aún, solo hay dos sistemas gestionados principales, el JVM y el CLR, y cuando dice "gestionado" es suficientemente explícito.
Boxeo automático y unboxing es lo único que sé. Los genéricos resuelven algunos problemas, pero lejos de muchos.
Sus genéricos son muy, muy débiles. Los genéricos de C # son considerablemente más fuertes, aunque, por supuesto, tampoco lo son las plantillas. La destrucción determinista es otra falta importante. Cualquier forma de lambda / cierre también es un problema importante: puede olvidar una API funcional en Java. Y, por supuesto, siempre existe el problema del rendimiento, para aquellas áreas que los necesitan.
fuente
Comenzaré con la condición de que sea casi imposible que alguien dé una opinión verdaderamente neutral sobre los lenguajes de programación. Si conoce dos idiomas lo suficientemente bien como para comentarlos de manera significativa, es casi inevitable que prefiera uno sobre el otro. Como advertencia, prefiero C ++ sobre Java, lo que sin duda influye en mis comentarios al menos hasta cierto punto.
1a. Velocidad: la velocidad que obtienes de C ++ o Java generalmente dependerá menos del lenguaje o su implementación que de la habilidad del programador que lo use. En última instancia, C ++ probablemente puede ganar velocidad a menudo, pero las diferencias en el código que escribes son lo que realmente importa.
1b. Si probablemente. Al mismo tiempo, C ++ ya está bien establecido, y dudo que la mayoría de los estudios de juegos vean la ventaja suficiente para molestarse en cambiar a Java.
1c. Una respuesta completa a esto probablemente podría llenar un gran volumen. C ++ generalmente funcionará mejor con recursos más limitados. Java se beneficia más de (por ejemplo) tener una gran cantidad de memoria "de reserva" disponible.
2. La ejecución lenta y la recolección lenta de basura probablemente serían las dos más obvias. La biblioteca de ventanas temprana (AWT) fue bastante torpe: Swing fue una mejora importante.
3. Verbosidad. Falta de sobrecarga del operador. Uso de la recolección de basura. Falta de herencia múltiple. Los genéricos de Java son extremadamente limitados en comparación con las plantillas C ++.
Debo agregar que algunas (¿todas?) De esas desventajas (especialmente el uso de la recolección de basura, pero las otras también) son vistas por muchos como ventajas de Java. La única excepción posible sería su verbosidad. La situación de verbosidad está mejorando un poco lentamente, pero ciertamente no se ven concursos de golf de código ganador de Java muy a menudo, y en el código ordinario también tiende a usar bastante código. Sospecho que hay al menos unos pocos que lo ven como más legible y comprensible, por lo que probablemente también pueda verse como una ventaja.
fuente
fuente
En primer lugar, algo de contexto, mi C ++ está muy oxidado, por lo que la mayoría de mis experiencias con Java se relacionan con mi experiencia más reciente con C #, que de todos modos es una comparación de manzanas a manzanas mucho más.
1. velocidad
Creo que esto se responde mejor con la pregunta SO ¿Por qué Java tenía la reputación de ser lento? pero también creo que toda esta pregunta está coloreada por la publicación del blog de Jeff Atwood, Gorilla vs. Shark . Gracias a Péter y Christopher.
Eso depende de las prioridades de los desarrolladores y las habilidades de los desarrolladores. Además, no se trata de una u otra situación, las diferentes partes del título pueden requerir diferentes elementos del idioma en el que se implementan, lo que lleva a un entorno de lenguaje heterogéneo.
Recientemente he visto varios juegos que mencionan que están cargando un entorno de Python mientras se están cargando y sospecho que los caballos para los cursos son una gran motivación si quieres obtener tu título a tiempo para la temporada de vacaciones (por ejemplo) .
Puede escribir código de bajo rendimiento en cualquier idioma, pero algunos idiomas hacen que sea más fácil tomar buenas decisiones, mientras que otros son más propensos a dejar que su propio imbécil lo levante . Java cae en la primera categoría, C ++ definitivamente cae en la última.
Con un gran poder viene una gran responsabilidad como dicen (sin mencionar la capacidad de arruinar completamente tu montón * 8 ').
2. ¿Se considera Java ahora un lenguaje compilado o un lenguaje interpretado?
No puedo decir lo que la mayoría de la gente considera que es, pero muchas personas saben la diferencia entre los idiomas compilados e interpretados, y no habían estado viviendo en una cueva durante los últimos 20 años, también sabrían que el JIT ( Just-in -Time ) es una parte importante del ecosistema de Java, por lo que es más probable que se considere compilado en estos días.
3. ¿Cuáles son algunas de las principales deficiencias de Java que se han abordado desde los primeros días?
Soy un converso bastante reciente a Java, por lo que tengo poco contexto sobre cómo ha evolucionado. Pero es interesante observar que hay libros como Java: The Good Parts que buscan dirigir a las personas en la dirección de las partes del lenguaje que deberían preferirse en estos días y alejar a las personas de las áreas que están, o deberían estar, obsoleto.
4. ¿Cuáles son algunas de las principales deficiencias de Java que aún no se han abordado?
En mi opinión, un problema con Java ha sido la lenta adopción de nuevas características.
Habiendo llegado a Java desde C #, y mirando a través de la página de comparación de Wikipedia , estas son las cosas que me destacan:
Cosas que extraño en Java, en comparación con C #
Cierres / lambdas . Estaba realmente decepcionado cuando escuché que el soporte de Java estaba siendo retrasado nuevamente .Finalmente tenemos Closures / lambdas en Java 8, pero el tiempo que tardó atestigua mi declaración sobre la adopción lenta.var
) puede parecer azúcar sintáctica, pero cuando tiene tipos genéricos complejos, puede hacer que el código sea mucho más claro al eliminar una gran cantidad de duplicaciones sin valor.struct
sobre una clase completa.Cosas que no extraño en Java, en comparación con C #
unsafe
código. Tienes que tener tanto cuidado con esto que rara vez he encontrado que valga la pena el esfuerzo extra.Como tal, incluso cuando se comparan manzanas con manzanas, se considera que Java se ha quedado atrás.
Los otros dos grandes problemas que veo con Java son el atroz retraso de inicio y el hecho de que (para algunas JVM) tiene que microgestión su montón e incluso el montón de generación permanente . Con C #, las aplicaciones siempre comenzaron de inmediato y nunca tuve que pensar en el montón, ya que se asignó fuera del grupo de memoria del sistema, no de un grupo asignado previamente asignado a la máquina virtual.
fuente
Puedo señalarle una fuente que puede ayudarlo a responder la primera parte de su pregunta. Los lenguajes de programación se disparan http://shootout.alioth.debian.org/u64q/which-programming-languages-are-fastest.php es una muy buena fuente para ver qué tan rápido se comparan los idiomas entre sí. Incluso se pueden filtrar en diferentes categorías para ver en qué áreas los idiomas funcionan mejor que otros. Java es mucho más rápido que hace varios años.
fuente
1) Hablando estrictamente sobre el UX que obtengo con Java, se siente lento. No puedo decirte por qué realmente. Todavía tengo que encontrar una aplicación de escritorio basada en Java, que no parezca lenta y tenga una alternativa más rápida que no sea Java. Dicho esto, Java puede ser muy rápido en velocidad computacional pura e Internet está lleno de puntos de referencia para demostrarlo. Sin embargo, el tiempo de arranque de las aplicaciones Java y la capacidad de respuesta de sus GUI aún no han mejorado en mi humilde opinión. Tal vez podría hacerlo;)
Al final, la velocidad no es tanto un problema. No solo el hardware se está volviendo cada vez más rápido, también es que a la mayoría de las personas todavía les importa sorprendentemente poco, siempre y cuando el software lo haga, lo que debería hacer y la relación entre el tiempo dedicado a interactuar y el tiempo dedicado a esperar es razonable.
2) Esta distinción se ha vuelto tan borrosa últimamente, que tiene muy poco valor.
3 + 4) En realidad, ha habido algunos cambios en Java. Algunas personas ya argumentan que estos cambios han contaminado la filosofía puramente simplista de Java al agregar características extrañas. Es realmente difícil decir objetivamente, qué es una deficiencia y qué fortaleza es. Para mí, Java es innecesariamente detallado, restrictivo y pobre en características, mientras que otras personas consideran estos mismos rasgos como una agradable ambigüedad, seguridad y claridad.
Entonces, si bien son estas cosas, las que personalmente me hacen no usar Java, no creo que simplemente sea una buena idea agregar las cosas que extraño en Java. Hay muchos lenguajes que me gusta ejecutar en la JVM y doblar Java para estar más cerca de ellos simplemente frustraría el propósito de Java.
Es una cuestión de preferencia
Lo que pasa con Java es que está diseñado para evitar que te dispares en el pie. Una causa noble, pero con todas las restricciones que te ata, no es improbable que tropieces con uno de tus pies seguros, no puedas asegurarte con las manos atadas a la espalda por tu propia seguridad y finalmente mueras, porque te rompes el cráneo : D
En cierto modo, Java fue una respuesta a C ++, que le da suficiente cuerda no solo para ahorcarse, sino también para el resto del mundo. Es toda esa cuerda, lo que la hace tan atractiva para los vaqueros. Toda esa libertad y todo ese poder.
En pocas palabras, esto es realmente solo una cuestión de preferencia.
Pero, un punto es que, con C ++ como alternativa a Java, puede elegir sus propias restricciones. O realmente volverse loco con todo el control que tiene, arriesgándose a confundir completamente a sus compañeros:
Java decidió no ofrecer la sobrecarga del operador, por esa misma razón. Por supuesto, esto evita que las personas ofusquen su código multiplicando punteros de función con listas. Pero al mismo tiempo evita que otras personas realicen cálculos geométricos / algebraicos con los operadores habituales.
(v1 * v2 / scale) + (v3 * m)
Realmente es mucho más claro quev1.multiply(v2).divide(scale).add(v3.multiply(m))
. Veo por qué esto puede desanimar a las personas que trabajan con gráficos en 3D y cálculos.Java eligió imponer la recolección de basura, mientras que en C ++ puede elegir. Realmente puedes cavar hasta el fondo y acercarte al hardware. Puede empaquetar datos densamente en estructuras. Puedes realizar magia oscura, como la raíz cuadrada inversa rápida . Puede realizar algunas de las metaprogramaciones más complicadas y crípticas en la tierra utilizando plantillas. Pero también significa que puede perderse y pasar horas depurando todo el desorden que creó o revisando errores de compilación absolutamente inútiles.
Pero si tiene la disciplina de usar solo las partes del lenguaje que realmente domina, puede escribir código C ++ con la misma seguridad que el código Java, pero tiene la opción de avanzar gradualmente.
Por lo tanto, aunque técnicamente nada le impide escribir software de vanguardia con Java, encontrará que muchos desarrolladores realmente se apasionan por escribir un excelente software y divertirse y evolucionar mientras lo hacen, más allá de lo que Java tiene para ofrecer como lenguaje.
Pero el mundo no consiste solo en personas establecidas, sino en crear la próxima gran cosa o solo en personas que restringirán el uso del poder que se les otorga solo en la medida en que lo controlen. En mi humilde opinión, Java es la combinación perfecta para las personas que desean producir resultados estables de una manera cómoda.
fuente
La recolección de basura es lo más importante. De vez en cuando, GC bloqueará todo lo demás durante varios cientos de milisegundos (según el tamaño del montón) y realizará una recopilación importante. Esto está bien si no tiene restricciones de tiempo, pero si llegar tarde significa un fracaso, esto es un obstáculo. Puede gastar el dinero en Java en tiempo real y en un sistema operativo en tiempo real, pero simplemente puede usar GCC y Linux estándar y no tendrá estos problemas.
Sin las pausas aleatorias impredecibles, Java es probablemente lo suficientemente rápido para la mayoría de las cosas en estos días. Y si pasa meses ajustando su configuración de GC y tal, tal vez, solo tal vez, puede hacer que funcione el tiempo suficiente para que el cliente le corte un cheque.
fuente
3) Deficiencias que se corrigieron.
Hace unos años había mucha rabia con Java. La mayoría de los programadores de Java son programadores web / servidor y se estaban volviendo locos con la verbosidad de Java. Así que algunos lenguajes como Ruby se hicieron populares y Java comenzó a menguar. Sin embargo, con las nuevas anotaciones y marcos como hibernate y Spring, la gente dejó de quejarse y volvió a Java.
4) Deficiencias actuales
El hardware se está volviendo multinúcleo. Aunque Java puede hacer multiproceso, se basa en C, que es un lenguaje secuencial y la funcionalidad para hacerlo multiproceso no es elegante, por decir lo menos. Por cierto, eso no es solo una crítica de Java, sino de casi todos los lenguajes. Se necesita una forma completamente diferente de pensar sobre el código. Tal vez la programación funcional es el camino del futuro.
fuente
De alguna manera reaccioné a esta pregunta porque dará respuestas engañosas y en gran medida irrelevantes:
Todos pueden estar de acuerdo en que los títulos AAA serían difíciles de producir usando Java y que no hay ejemplos reales que yo sepa. Sin embargo, dada la naturaleza de AAA, eso supondría muchas cosas (ya que realmente es un término confuso que proviene del marketing), por lo que es mejor preguntar lo siguiente:
La respuesta es " Sí, puedes ". Sin embargo, la parte del éxito real de la ecuación se basa más en su persistencia y suerte (o adhesión al espíritu de la época), pero eso está fuera del alcance de este sitio.
fuente
Un área certian de velocidad se reduce a compilador vs compilador. No lenguaje vs lenguaje. La compilación JIT puede tener ventajas, ya que puede optimizar las especificaciones de la máquina en la que se está ejecutando. Compare J ++ compilado C ++ versus Java para obtener una comparación del compilador más "manzanas con manzanas".
Pero hay algunas cosas en las que el lenguaje Java en sí limita su propio rendimiento.
asignación en la pila. Java no puede hacer esto. Para clases pequeñas de tamaño fijo en una solución no recursiva, esto suele ser ideal. También puede evitar la fragmentación del montón.
funciones no virtuales Java no puede hacer esto. Todas las llamadas a métodos reciben un impacto permanente incluso cuando no se planea anularlas.
Probablemente algunas otras cosas, pero eso es todo lo que puedo pensar fuera de mi cabeza.
fuente
1) irrelevante y argumentativo para arrancar.
No solo se pueden crear las principales piezas de software en Java, sino que estos sistemas se entregan todos los días y ahora funcionan con la mayoría de las principales empresas del mundo.
2) lo mismo.
Lea la especificación JVM y lo sabrá. Java nunca fue un lenguaje interpretado.
3) lo mismo.
Lea los 15 años de notas de lanzamiento. Imposible que descubramos qué considera que deben abordarse "fallas importantes".
4) lo mismo.
El principal defecto que debe abordarse es el JCP, que es propenso a entrometerse con el lenguaje central y las bibliotecas sin otra razón aparente que obtener el nombre de somoene en un JSR para que puedan escribir un libro con un comentario autoritario que "ellos fueron líder de JSR-666 ". Esperemos que la reestructuración de Oracle del JCP se encargará de eso.
Parece que solo quieres provocar una guerra de idiomas aquí, y que tus prejuicios contra Java sean confirmados por otros porque no puedes encontrar ninguna justificación real para ti.
fuente