Crítica de Java - Criticism of Java

El lenguaje de programación Java y la plataforma de software Java han sido criticados por elecciones de diseño que incluyen la implementación de genéricos, programación forzada orientada a objetos, el manejo de números sin firmar, la implementación de aritmética de punto flotante y un historial de vulnerabilidades de seguridad en el Java primario. Implementación de VM, HotSpot . El software escrito en Java, especialmente sus primeras versiones, ha sido criticado por su rendimiento en comparación con el software escrito en otros lenguajes de programación. Los desarrolladores también han señalado que las diferencias en varias implementaciones de Java deben tenerse en cuenta al escribir programas complejos de Java que deben funcionar con todas ellas.

Sintaxis y semántica del lenguaje

Genéricos

Cuando se agregaron los genéricos a Java 5.0, ya existía un gran marco de clases (muchas de las cuales ya estaban en desuso ), por lo que los genéricos se implementaron utilizando el borrado de tipos para permitir la compatibilidad de la migración y la reutilización de estas clases existentes. Esto limitó las funciones que se podían proporcionar, en comparación con otros idiomas.

Debido a que los genéricos se implementan mediante el borrado de tipos, el tipo real de un parámetro de plantilla E no está disponible en tiempo de ejecución. Por tanto, las siguientes operaciones no son posibles en Java:

public class MyClass<E> {
    public static void myMethod(Object item) {
        if (item instanceof E) {  //Compiler error
            ...
        }
        E item2 = new E();   //Compiler error
        E[] iArray = new E[10]; //Compiler error
    }
}

Orientación sustantiva

Por diseño, Java anima a los programadores a pensar en una solución en términos de sustantivos (clases) que interactúan entre sí, y a pensar en los verbos (métodos) como operaciones que se pueden realizar en o por ese sustantivo. Steve Yegge sostiene que esto provoca una restricción innecesaria en la expresividad del lenguaje porque una clase puede tener múltiples funciones que operan en ella, pero una función está ligada a una clase y nunca puede operar en múltiples tipos.

Muchos otros lenguajes de múltiples paradigmas admiten funciones como una construcción de nivel superior. Cuando se combina con otras características como la sobrecarga de funciones (un verbo, varios sustantivos) y funciones genéricas (un verbo, una familia de sustantivos con ciertas propiedades), el programador puede decidir si resolver un problema específico en términos de sustantivos o verbos. La versión 8 de Java introdujo algunas características de programación funcional.

Relación oculta entre código y hardware

En 2008, el Centro de Soporte Tecnológico de Software del Departamento de Defensa de los Estados Unidos publicó un artículo en el "Journal of Defense Software Engineering" en el que se discutía la inadecuación de Java como primer idioma que se enseña. Las desventajas eran que los estudiantes "no tenían idea de la relación entre el programa fuente y lo que haría realmente el hardware" y la imposibilidad "de desarrollar una idea del costo en tiempo de ejecución de lo que está escrito porque es extremadamente difícil saber qué la llamada al método eventualmente se ejecutará ". En 2005, Joel Spolsky criticó a Java como una parte demasiado concentrada de los planes de estudio de las universidades en su ensayo The Perils of JavaSchools . Otros, como Ned Batchelder, no están de acuerdo con Spolsky por criticar las partes del lenguaje que le resultaban difíciles de entender, afirmando que el comentario de Spolsky era más una "perorata subjetiva".

Tipos de enteros sin signo

Java carece de tipos enteros nativos sin signo . Los datos sin firmar a menudo se generan a partir de programas escritos en C , y la falta de estos tipos evita el intercambio directo de datos entre C y Java. Los números grandes sin firmar también se utilizan en varios campos de procesamiento numérico, incluida la criptografía, lo que puede hacer que Java sea más incómodo para estas tareas. Aunque es posible solucionar este problema utilizando código de conversión y tipos de datos más grandes, hace que el uso de Java sea engorroso para manejar datos sin firmar. Mientras que un entero de 32 bits con signo se puede utilizar para contener un valor sin signo de 16 bits sin pérdidas, y un entero de 64 bits con signo, un entero sin signo de 32 bits, no existe un tipo más grande para contener un entero de 64 bits sin signo. En todos los casos, la memoria consumida puede duplicarse y, por lo general, cualquier lógica que dependa del desbordamiento del complemento a dos debe reescribirse. Si se abstraen, las llamadas a funciones se vuelven necesarias para muchas operaciones que son nativas de algunos otros lenguajes. Alternativamente, es posible usar enteros con signo de Java para emular enteros sin signo del mismo tamaño, pero esto requiere un conocimiento detallado de las operaciones bit a bit . En JDK 8 se proporcionó cierto soporte para los tipos de enteros sin firmar, pero no para los bytes sin firmar y sin soporte en el lenguaje Java.

Sobrecarga del operador

Java ha sido criticado por no admitir operadores definidos por el usuario. La sobrecarga del operador mejora la legibilidad, por lo que su ausencia puede hacer que el código Java sea menos legible, especialmente para las clases que representan objetos matemáticos, como números complejos y matrices. Java tiene un solo uso no numérico de un operador: +para la concatenación de cadenas. Pero esto lo implementa el compilador, que genera código para crear instancias de StringBuilder; es imposible crear sobrecargas de operadores definidos por el usuario.

Tipos de valor compuesto

Java carece de tipos de valores compuestos, como estructuras en C, paquetes de datos que se manipulan directamente en lugar de indirectamente a través de referencias. Los tipos de valor a veces pueden ser más rápidos y más pequeños que las clases con referencias. Por ejemplo, Java HashMapse implementa como una matriz de referencias a HashMap.Entryobjetos, que a su vez contienen referencias a objetos clave y de valor. Buscar algo requiere una doble desreferenciación ineficiente. Si Entryfuera un tipo de valor, la matriz podría almacenar pares clave-valor directamente, eliminando la primera indirecta, aumentando la localidad de referencia y reduciendo el uso de memoria y la fragmentación del montón . Además, si Java admitía tipos primitivos genéricos, las claves y los valores podrían almacenarse en la matriz directamente, eliminando ambos niveles de indirección.

Grandes matrices

Java ha sido criticado por no admitir matrices de 2 31 (alrededor de 2,1 mil millones) o más elementos. Esta es una limitación del idioma; la Especificación del lenguaje Java , Sección 10.4, establece que:

Las matrices deben estar indexadas por valores int ... Un intento de acceder a un componente de matriz con un valor de índice largo da como resultado un error en tiempo de compilación.

La compatibilidad con matrices grandes también requeriría cambios en la JVM. Esta limitación se manifiesta en áreas tales como que las colecciones estén limitadas a 2 mil millones de elementos y la imposibilidad de mapear en memoria segmentos de archivos continuos mayores de 2 GB. Java también carece de matrices multidimensionales (bloques únicos de memoria asignados de forma contigua a los que se accede mediante una única dirección indirecta), lo que limita el rendimiento de la informática científica y técnica.

No existe una forma eficaz de inicializar matrices en Java. Al declarar una matriz, la JVM la compila en códigos de bytes con instrucciones que establecen sus elementos uno por uno en tiempo de ejecución. Debido a que los métodos Java no pueden superar los 64 KB, las matrices de tamaños incluso modestos con valores asignados directamente en el código mostrarán el mensaje "Error: código demasiado grande" en la compilación.

Integración de primitivas y matrices

Las matrices y primitivas son algo especiales y deben tratarse de manera diferente a las clases. Esto ha sido criticado porque requiere muchas variantes de funciones al crear bibliotecas de propósito general.

Paralelismo

Per Brinch Hansen argumentó en 1999 que la implementación de Java del paralelismo en general, y los monitores en particular, no proporciona las garantías y el cumplimiento necesarios para una programación paralela segura y confiable. Mientras que un programador puede establecer convenciones de diseño y codificación , el compilador no puede intentar hacerlas cumplir, por lo que el programador puede escribir sin saberlo código inseguro o poco confiable.

Publicación por entregas

Java proporciona un mecanismo llamado serialización de objetos, donde un objeto se puede representar como una secuencia de bytes que incluye sus campos de datos, junto con información de tipo sobre sí mismo y sus campos. Una vez que se serializa un objeto, se puede deserializar posteriormente; es decir, la información de tipo y los bytes que representan sus datos se pueden usar para recrear el objeto en la memoria. Esto plantea riesgos de seguridad reales y teóricos muy graves.

Aritmética de coma flotante

Aunque la aritmética de coma flotante de Java se basa en gran medida en IEEE 754 ( Estándar para aritmética de coma flotante binaria ), algunas características estándar obligatorias no son compatibles incluso cuando se usa el strictfpmodificador, como los indicadores de excepción y los redondeos dirigidos. Los tipos de precisión extendida definidos por IEEE 754 (y compatibles con muchos procesadores) no son compatibles con Java.

Rendimiento

Antes de 2000, cuando HotSpot VM se implementó en Java 1.3, hubo muchas críticas sobre su rendimiento. Se ha demostrado que Java se ejecuta a una velocidad comparable con el código nativo optimizado, y las implementaciones modernas de JVM se evalúan regularmente como una de las plataformas de lenguaje más rápidas disponibles, por lo general, no más de tres veces más lento que C y C ++.

El rendimiento ha mejorado sustancialmente desde las primeras versiones. Se ha demostrado que el rendimiento de los compiladores JIT en relación con los compiladores nativos es bastante similar en algunas pruebas optimizadas.

El código de bytes de Java puede ser interpretado en tiempo de ejecución por una máquina virtual o compilado en tiempo de carga o en tiempo de ejecución en código nativo que se ejecuta directamente en el hardware de la computadora. La interpretación es más lenta que la ejecución nativa, pero la compilación en tiempo de carga o en tiempo de ejecución tiene una penalización de rendimiento inicial. Todas las implementaciones modernas de JVM utilizan el enfoque de compilación, por lo que después del tiempo de inicio inicial, el rendimiento es similar al del código nativo.

El diseñador y programador de juegos John D. Carmack concluyó en 2005 sobre Java en teléfonos móviles : "El mayor problema es que Java es realmente lento. En un nivel puro de cpu / memoria / pantalla / comunicaciones, la mayoría de los teléfonos móviles modernos deberían ser considerablemente mejores para juegos plataformas que una Game Boy Advance. Con Java, en la mayoría de los teléfonos te quedas con la potencia de CPU de una PC IBM original de 4,77 mhz (sic) y un pésimo control sobre todo ".

Seguridad

La plataforma Java proporciona una arquitectura de seguridad que está diseñada para permitir que el usuario ejecute un código de bytes que no es de confianza en una forma de "espacio aislado" para protegerse contra software malintencionado o mal escrito. Esta función de "espacio aislado" está destinada a proteger al usuario al restringir el acceso a las funciones de la plataforma y las API que podrían ser explotadas por malware , como el acceso al sistema de archivos o la red local, o la ejecución de comandos arbitrarios.

En 2010, hubo un aumento significativo en el software malicioso dirigido a fallas de seguridad en los mecanismos de espacio aislado utilizados por las implementaciones de Java, incluida la de Oracle. Estas fallas permiten que el código que no es de confianza eluda las restricciones de la zona de pruebas, exponiendo al usuario a ataques. Las fallas se corrigieron mediante actualizaciones de seguridad, pero aún se aprovecharon en máquinas sin las actualizaciones.

Los críticos han sugerido que los usuarios no actualicen sus instalaciones de Java porque no saben que las tienen o cómo actualizarlas. Muchas organizaciones restringen la instalación de software por parte de los usuarios, pero implementan actualizaciones con lentitud.

Oracle ha sido criticado por no proporcionar rápidamente actualizaciones para errores de seguridad conocidos. Cuando Oracle finalmente lanzó un parche para fallas ampliamente explotadas en Java 7, eliminó Java 6 de las máquinas de los usuarios, a pesar de ser ampliamente utilizado por aplicaciones empresariales que, según Oracle, no se vieron afectadas por las fallas.

En 2007, un equipo de investigación dirigido por Marco Pistoia expuso otra falla importante del modelo de seguridad de Java, basada en la inspección de pila . Cuando se accede a un recurso sensible a la seguridad, el administrador de seguridad activa un código que recorre la pila de llamadas, para verificar que el código base de cada método tiene autoridad para acceder al recurso. Esto se hace para evitar confusos ataques de diputados , que tienen lugar cada vez que un programa legítimo y más privilegiado es engañado por otro para que haga un mal uso de su autoridad. El problema del diputado confuso es un tipo específico de escalada de privilegios . Pistoia observó que cuando se accede a un recurso sensible a la seguridad, es posible que el código responsable de adquirir el recurso ya no esté en la pila. Por ejemplo, un método ejecutado en el pasado puede haber modificado el valor de un campo de objeto que determina qué recurso usar. Es posible que esa llamada al método ya no esté en la pila cuando se inspecciona.

Algunos permisos son implícitamente equivalentes a los de Java AllPermission. Estos incluyen el permiso para cambiar el administrador de seguridad actual (y reemplazarlo con uno que podría pasar por alto la inspección de la pila), el permiso para crear una instancia y usar un cargador de clases personalizado (que podría optar por asociarse AllPermissiona una clase maliciosa al cargarlo), y el permiso para crear un permiso personalizado (que podría declararse tan poderoso como a AllPermissiontravés de su impliesmétodo). Estos problemas están documentados en los dos libros de Pistoia sobre seguridad Java : Java 2 Network Security (segunda edición) y Enterprise Java Security .

Instalaciones paralelas

Antes de Java 7, era normal que el instalador no detectara ni eliminara instalaciones de Java más antiguas. Era bastante común en una computadora con Windows ver múltiples instalaciones de Java 6 en la misma computadora, variando solo por una revisión menor. Se permiten múltiples instalaciones y pueden ser utilizadas por programas que dependen de versiones específicas.

Esto tiene el efecto de que las nuevas instalaciones de Java pueden proporcionar nuevas funciones de lenguaje y correcciones de errores, pero no corrigen las vulnerabilidades de seguridad, porque los programas maliciosos pueden utilizar las versiones anteriores.

Java 7 actualizó versiones anteriores de sí mismo, pero no Java 6 o anteriores.

Actualizaciones automáticas

A partir de 2014, las herramientas comunes de terceros (como Adobe Flash y Adobe Reader) han sido objeto de escrutinio en busca de vulnerabilidades de seguridad. Adobe y otros se han trasladado a las actualizaciones automáticas en Windows. Estos no necesitan ninguna acción por parte del usuario y garantizan que los problemas de seguridad se resuelvan rápidamente con un esfuerzo mínimo por parte de los usuarios o administradores.

A partir de 2015, Java 8 todavía requiere que los usuarios actualicen Java ellos mismos. Pero en Windows solo aquellos con privilegios de administrador pueden actualizar el software. El actualizador de Java de Windows activa con frecuencia un aviso de elevación de Control de cuentas de usuario disruptivo: independientemente de lo que elijan los usuarios, seguirán recibiendo el mismo mensaje "Java debe actualizarse".

Ver también

Notas

enlaces externos