Software
Java
Código
Desarrollo

11 razones por las que el nuevo Java no es como el antiguo

Java ya no es el lenguaje que era, y eso es algo positivo. He aquí once formas en las que Java está evolucionando para afrontar los retos del futuro.

java

¿Java ya es historia? ¿El tipo de lenguaje de programación utilizado por los veteranos que parlotean sobre paneles frontales con luces parpadeantes y los días de los disquetes? ¿O sigue estando de moda, con todas las últimas mejoras del lenguaje para una codificación intuitiva y un rendimiento de primera? Quizás Java se encuentre en algún punto intermedio: un lenguaje maduro, pero joven de corazón.

Hace casi 30 años, el 23 de mayo de 1995, Java llegó oficialmente al mundo. Empezó como una tecnología habilitadora llamada "Oak" para un equipo que Sun Microsystems imaginó que pronto colonizaría el salón de casa de los estadounidenses. El plan no salió bien, al menos al principio. Pero el lenguaje se convirtió en una de las bases del software moderno, que funciona en todo tipo de dispositivos, desde pequeños chips sensores hasta grandes servidores.

Desde entonces, la idea de Java ha cambiado radicalmente. Sun y Oracle han hecho un trabajo extraordinario insertando características que mantienen fresco el lenguaje sin alterar gran parte de la funcionalidad básica. Puede que Java sea uno de esos lenguajes que siguen avanzando.

Una cosa que sabemos con certeza es que muchas de las características que viven dentro de la gran carpa llamada "Java" son diferentes de lo que se previó originalmente, a menudo de forma radical. Los programadores están creando código que la gente de 1995, 2005 o incluso 2015 no reconocería, pero el código antiguo sigue funcionando. Eso es una curación de alta calidad. Oracle, la empresa que compró Sun en 2010, ofrece ahora nuevas versiones con regularidad y añade funciones que mantienen la relevancia del lenguaje Java.

Aquí hay once maneras en que Java ha cambiado, en su mayoría para mejor.

 

10 formas en que la programación en Java es mejor que antes (y una razón por la que no lo es)

  • Threads virtuales
  • Concurrencia estructurada
  • Datos inmutables
  • Recogida de basura
  • Concordancia de patrones
  • Sintaxis simplificada
  • Clases selladas
  • Funciones externas y memoria
  • La API Vector
  • Procesamiento de nulos mejorado
  • Gratuito como en ... ¿licencia de pago?

 

Threads virtuales

La versión original de Java ofrecía a los desarrolladores la posibilidad de crear sus propios objetos Thread y controlar cómo se ejecutaba el código en entornos multithread y multinúcleo. Aunque era mejor que nada, los programadores aprendieron rápidamente que los objetos Thread eran bastante grandes y tardaban demasiado tiempo en crearse y destruirse. La creación de un grupo de threads permanente al inicio de un programa se convirtió en una solución común para los threads pesados.

Todo esto cambió en Java 19, con la llegada de los threads virtuales. Ahora, JVM se encarga de gran parte del trabajo de distribución de los recursos del sistema en los programas Java. Los programadores especifican cuándo está disponible el paralelismo y el runtime JVM ejecuta el código de forma concurrente siempre que puede. Los threads virtuales son una bendición para arquitecturas modernas como los microservicios, que son más fáciles de desarrollar y soportar.

 

Concurrencia estructurada

Los threads más ligeros son sólo el principio. Java está añadiendo un modelo abstracto de paralelismo que facilitará a los programadores y a JVM el procesamiento concurrente de cargas de trabajo. El nuevo modelo de concurrencia estructurada ofrece al programador la posibilidad de dividir una carga de trabajo Java en tareas, que luego se agrupan en ámbitos. Los ámbitos se agrupan en fibras que trabajan juntas en el mismo thread.

El objetivo es ofrecer a los desarrolladores de Java un modelo estándar para crear programas paralelos, de modo que no tengan que razonar profundamente sobre ello cada vez. La concurrencia estructurada también facilita a la máquina virtual la detección de oportunidades de ejecución concurrente y su asignación a los núcleos del procesador.

 

Datos inmutables

Al principio, los strings estaban grabados en piedra. Una vez que un string era creado, nunca podía ser cambiado. Llamar a una función como toLowerCase crearía un string completamente nuevo. Esto simplificaba a JVM la gestión de la seguridad y la sincronización entre threads.

Ahora, los programadores Java pueden especificar las mismas reglas inmutables para sus propios objetos llamándolos "Registros". Esto simplifica la seguridad, el almacenamiento en caché y la sincronización entre threads. El código enumera los nombres y tipos de los campos y la JVM se encarga del resto. Los métodos comunes como equals, hashCode y toString se crean automáticamente. El resto del tiempo, la JVM se encarga de que los Registros sean inmutables, lo que simplifica muchos detalles del programa y acelera la ejecución del código.

 

Recogida de basura

Java siempre ha gestionado muchos de los detalles de la asignación y recuperación de memoria, una función que muchos programadores están encantados de delegar en la JVM. A veces, sin embargo, el recolector de basura original hacía pausas lo suficientemente largas como para que los usuarios se dieran cuenta de que el rendimiento bajaba.

Hoy en día, los programadores pueden elegir entre cuatro recolectores de basura, que utilizan una variedad de algoritmos de recolección de basura diferentes y están especializados para diferentes tipos de aplicaciones:

  • El Recolector de Basura Garbage First (G1) es la opción por defecto, ya que ofrece un mejor rendimiento con pausas más cortas. G1 emplea técnicas que se han desarrollado a partir de las lecciones aprendidas de iteraciones anteriores de la recolección de basura de Java, como barajar los bloques más grandes y el reconocimiento afinado de objetos pequeños que cambian con frecuencia.
  • El Recolector de Basura Z está diseñado para tener una latencia muy baja, un requisito para los servidores web, los servicios de streaming y otros trabajos con datos en tiempo real. También puede funcionar bien con un volumen muy grande porque fue diseñado para escalar a 16 terabytes de RAM.
  • El Recolector de Basura Concurrente se ejecutará en segundo plano sin detener la aplicación en absoluto. Es mejor para trabajos como aplicaciones interactivas que no deben detenerse nunca, aunque puede no ser tan eficiente.
  • Por último, el Recolector de Basura Paralelo utiliza múltiples threads para recolectar datos más rápidamente, pero las paradas son más impredecibles.

Los desarrolladores no están atascados con un único método para la recolección de basura, y no tienen que recurrir a otras soluciones como simular su propia gestión de memoria reutilizando objetos. Ahora hay cuatro opciones principales y cada una de ellas ofrece opciones para un mayor ajuste y experimentación.

 

Concordancia de patrones con switch

El equipo de Java también ha mejorado el lenguaje en algunos de los niveles sintácticos más bajos, dando a los desarrolladores más opciones para escribir una lógica más limpia y expresiva. La palabra clave switch, utilizada para crear pilas de condicionales if-then-else, ofrece ahora concordancia de patrones, lo que significa que la lógica para especificar los distintos casos no se limita a expresiones básicas como equals.

El código Java escrito con estos patrones es especialmente conciso, y es capaz de hacer distinciones no sólo en el valor de los datos, sino también en el tipo de objeto. Se pueden utilizar todos los tipos de referencia y el puntero nulo. Por supuesto, la lógica más tradicional con semántica fall-through sigue siendo compatible para que el código antiguo siga funcionando sin problemas.

 

Sintaxis simplificada

Al principio, escribir en Java no era muy diferente de escribir en C o C++. Las llaves y los puntos y coma hacían en Java prácticamente lo mismo que en C. Los bucles se estructuraban con la clásica forma de tres partes. Aunque sus entrañas guardaban una profunda conexión con Lisp, la sintaxis básica de Java no era muy diferente de la de C.

Sin embargo, las adiciones más recientes se han inspirado en la simplicidad de lenguajes de programación como Ruby y Python. Los bucles For ya no tienen que detallarse, porque el compilador puede intuirlos cuando se recorre una lista o una matriz. Las funciones anónimas y las expresiones lambda también son buenas opciones para los programadores que quieren ahorrar pulsaciones.

Algunas de las palabras y el exceso de puntuación de C siguen ahí, pero los programadores Java de hoy en día pueden explicar estructuras complejas con menos caracteres.

 

Clases selladas

Desde el principio, la JVM se diseñó para evitar muchos agujeros de seguridad comunes que los programadores podrían dejar en sus programas por error. Las versiones más recientes han añadido aún más opciones. Las clases selladas, por ejemplo, permiten al creador de la clase especificar exactamente qué clases pueden extenderla. Así se evita que otra persona que utilice una biblioteca extienda una clase y añada o anule parte de la funcionalidad original.

Las clases selladas también funcionan un poco más rápido que las tradicionales porque permiten una optimización y un inlining más agresivos. También pueden simplificar el envío de métodos.

 

Funciones externas y memoria

La máquina virtual Java fue diseñada para ser un jardín amurallado o un sandbox. La máquina virtual protege el código y evita muchos ataques generales que son posibles cuando el código se ejecuta de forma nativa.

Para los programadores entendidos, la interfaz nativa de Java (JNI) original era una especie de puerta trasera. El equipo de Java sabía que algunos desarrolladores necesitaban conectarse a bibliotecas y pilas escritas en otros lenguajes, y que algunas llamadas al sistema eran esenciales. Así que abrieron este agujero en la armadura de la JVM, con una simple advertencia sobre los peligros de su uso.

Ahora, tenemos la API de función externa y memoria, actualmente un JEP en tercera vista previa. Esta API haría más fácil y segura la conexión con el exterior. Ahora se puede escribir mucho más en Java puro, abriendo oportunidades para que los programadores asiduos de Java empiecen a conectarse a la memoria general del sistema. La propuesta también añade mejores barandillas, como la comprobación de tipos, para bloquear algunos de los peores ataques potenciales de desbordamiento.

Esta API facilitaría que el código Java asumiera más tareas de bajo nivel y procesamiento de datos en la codificación del sistema. Es una forma más segura de que los programadores de Java empiecen a salir del sandbox.

 

La API Vector

La clase Vector original, conocida por muchos programadores veteranos de Java, era más una estructura de datos y menos una herramienta matemática. Era una solución flexible y sincronizada para almacenar objetos que no se diferenciaba mucho de List.

La nueva API Vector es mucho más que eso. Es una herramienta para el tipo de procesamiento matemático de datos cada vez más habitual, ya que los algoritmos de inteligencia artificial utilizan matrices y vectores más o menos del mismo modo que los físicos y los matemáticos. Los elementos individuales pueden ser tipos primitivos y se admiten muchas de las operaciones matemáticas básicas, como los productos punto.

Una buena manera de ver la diferencia entre la clase Vector y la API es ver lo que hace el método add. En la clase original, simplemente añade un objeto al final de la estructura de datos, como hacen todas las demás clases Collections. En la API, se utiliza para agregar matemáticamente los elementos individuales, más como un ingeniero esperaría.

La API Vector también promete aprovechar la enorme capacidad de cálculo de algunos de los procesadores SIMD más recientes, lo que permitirá a los programadores de Java crear código capaz de procesar muchos vectores largos.

 

Mejor procesamiento de nulos

¿Es ese objeto un puntero nulo? Gran parte del código Java se dedica a comprobar, volver a comprobar y, a continuación, volver a comprobar los objetos. Para simplificar el código y acelerar un poco las cosas, Java ha ido añadiendo poco a poco funciones que gestionan los punteros nulos de una forma más elegante. La API Stream, por ejemplo, puede procesar largos flujos de datos y no se bloqueará si aparece un valor nulo ocasional. La envoltura de la clase Optional puede o no contener un objeto real, lo que permite que el código fluya sin problemas. Y si todavía quieres comprobar si hay nulos, existe el operador null-safe (?.) que comprueba si hay nulos de una forma muy concisa.

 

¿Gratuito como en... licencia de pago?

Java siempre ha sido prácticamente gratuito, al menos para los programadores. Desde el principio, Sun quiso atraer a los desarrolladores con herramientas y hardware gratuitos, y en 1997 la empresa dio el audaz paso de abrir muchas partes del lenguaje y su máquina virtual. Hasta hace poco, los programadores podían más o menos escribir una vez y ejecutar en cualquier sitio sin pagar un céntimo.

Ahora, el panorama es más turbio. Muchas versiones de Java de Oracle son gratuitas, pero otras exigen una licencia con condiciones extrañas. Parece que Oracle quiere que los programadores disfruten de la libertad de crear sin limitaciones monetarias, pero también quiere extraer un impuesto o renta de las empresas que generan importantes ingresos a largo plazo con Java. En la práctica, esto significa cobrar por lo que Oracle denomina funciones de suscripción de Java. Así pues, Java sigue siendo gratuito, a menos que quieras actualizarlo para uso comercial.



Contenido Patrocinado

Forma parte de nuestra comunidad

 

¿Te interesan nuestras conferencias?

 

 
Cobertura de nuestros encuentros
 
 
 
 
Lee aquí nuestra revista de canal

DealerWorld Digital