Java 11 es la versión LTS (Long Term Support). Esto significa que tendrá soporte y actualizaciones durante 3 años, en lugar de solo 6 como el resto de versiones no LTS.
A partir de Java 11 Oracle no proveerá la JDK de forma libre para uso comercial. Es decir, si deseas usar Java 11 para uso comercial deberás pagar una licencia.
Las versiones anteriores a JDK 11 seguirán siendo gratuitas por lo que si usas Java 8, 9 o 10 no deberás pagar, salvo que necesites soporte o actualizaciones de seguridad o parches ( gracias Oracle :/ ).
La verdad, que este cambio de licencia para Java no lo veo positivo sin embargo siempre puedes optar por utilizar OpenJDK u otras alternativas como la JDK de Amazon Corretto [https://aws.amazon.com/es/corretto/]1
El cambio de licencia a partir de Java 11 no implica que Java deje de ser gratuito. Quien no desee entrar en el esquema de licencias de Oracle podrá trasladarse a OpenJDK o a otras JDK alternativas y con buen soporte de la comunidad. Claro si se trata de una empresa quizás considere más fiable abonarse con Oracle.
A continuación te resumo las novedades en Java 11 que considero más interesantes.
Ejecutar archivos Java directamente sin javac
Este cambio lo que te permite ahora es ejecutar un file java directamente sin necesidad de compilarlo previamente con javac.
Ahora puedes directamente correr tu programa java y esto ya implica una compilación previa.
// HelloWorldExample.java
public class HelloWorldExample {
public static void main(String[] args) {
System.out.println("Hello World!!");
}
}
$ java HelloWorldExample.java
Hello World!!
Java String
Java 11 introduce algunos métodos nuevos para nuestros Strings.
isBlank() Este nuevo método retorna un valor booleano según si el string contiene solo espacios en blanco y si está vacío.
lines() Este metodo devolvera un array de strings ‘spliteando’ el texto por lineas.
strip(), stripLeading(), stripTrailing() Remueve los caracteres en blanco. A diferencia del viejo trim(), este nuevo método strip si tiene en cuenta los caracteres Unicode.
Character.isWhitespace(c) nos permite saber si un carácter es considerado un blanco.
repeat(int) Repite el string las veces que se le indique.
import java.util.stream.Collectors;
public class StringExample {
public static void main(String[] args) {
//isBlank() example
System.out.println(" ".isBlank());
String s = "Hi Word!";
System.out.println(s.isBlank());
String s1 = "";
System.out.println(s1.isBlank());
System.out.println();
// lines() example
String str = "Hi\nWord\nHi\nUniverse";
System.out.println(str);
System.out.println(str.lines().collect(Collectors.toList()));
System.out.println();
// strip() example
String hello = " HELLO ";
System.out.println("SAY" + hello.strip() + "PLEASE");
System.out.println("SAY" + hello.stripLeading() + "PLEASE");
System.out.println("SAY" + hello.stripTrailing() + "PLEASE");
System.out.println();
Character c = '\u2000';
String stringWithUnicode = c + "abc" + c;
System.out.println("Contain unicode " + Character.isWhitespace(c));
System.out.println("Trim test " + (stringWithUnicode == stringWithUnicode.trim()) );
System.out.println("Strip test " + ("abc"== stringWithUnicode.strip()));
System.out.println();
// repeat() example
String rep = "HI".repeat(2);
System.out.println(rep);
System.out.println();
}
}
La salida de este código
true
false
true
Hi
Word
Hi
Universe
[Hi, Word, Hi, Universe]
SAYHELLOPLEASE
SAYHELLO PLEASE
SAY HELLOPLEASE
Contain unicode true
Trim test true
Strip test false
HIHI
Variables Locale para los parámetros Lambda
En Java 10 se introdujo el uso de var con inferencia del tipo. Ahora podemos usar esto en la declaración de lambdas.
(var s1, var s2) -> s1 + s2
Esto a su vez permite el uso de anotaciones en los parámetros de la función por ejemplo @NotNull
(@NotNull var s1, @NotNull var s2) -> s1 + s2
@NotNull var foo = new Foo()
Si se usa var se debe usar en todas las variables. Es decir no podríamos hacer esto combinando un var con un int por ejemplo
(var s1, int s2) -> s1 + s2 // no compila
Cliente HTTP
En Java 11 quedó estable el cliente Http que se había introducido de forma experimental en Java 9. Este cliente Http soporta http/1.1 y http/2. Está diseñado para realizar llamadas a servicios de forma simple y recibir las respuestas desde el servicio. Podemos encontrar este nuevo cliente dentro del paqute java.net.http. Esto nos libera del uso de otras librerías para llamadas sencillas a servicios http.
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class HttpClientExample {
public static void main(String[] args) throws IOException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com"))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
Lectura y escritura de String en archivos
En Java 11 se agregaron estos dos métodos que nos simplificarán la lectura y escritura de texto sobre archivos.
- readString(Path)
- readString(Path, Charset)
- writeString(Path, CharSequence, OpenOption…)
- writeString(Path, CharSequence, Charset, OpenOption…)
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class FileReadStringExample {
public static void main(String[] args) throws IOException {
Path path = Files.writeString(
Files.createTempFile(
"myfile", ".txt"),
"This was posted on JD");
String s = Files.readString(path);
System.out.println(s);
}
Acceso a clases internas
En Java 11 se agregaron nuevos métodos para acceder via reflexión a los métodos internos.
La clase java.lang.Class introduce tres metodos getNestHost(), getNestMembers(), y isNestmateOf().
En Java puedes hacer algo como esto en donde desde una clase interna accedes a un método privado de la clase externa.
public class Outer {
public void outerPublic() {
}
private void outerPrivate() {
}
class Inner {
public void innerPublic() {
outerPrivate();
}
}
}
Si intentas mediante reflexión acceder al método privado recibirás una excepción.
import java.lang.reflect.Method;
public class OuterReflection {
public static void main(String[] args) throws Exception {
Outer ob = new Outer();
Method method = ob.getClass().getDeclaredMethod("outerPrivate");
method.invoke(ob);
}
}
Exception in thread "main" java.lang.IllegalAccessException: class j11.OuterReflection cannot access a member of class j11.Outer with modifiers "private"
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:361)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:591)
at java.base/java.lang.reflect.Method.invoke(Method.java:558)
at j11.OuterReflection.main(OuterReflection.java:10)
Veamos como en Java 11 se resuelve este problema
import java.lang.reflect.Method;
public class OuterReflection {
public static void main(String[] args) throws Exception {
Outer ob = new Outer();
// Method method = ob.getClass().getDeclaredMethod("outerPrivate");
// method.invoke(ob);
// new in J11
Method method = ob.getClass().getNestHost().getDeclaredMethod("outerPrivate");
method.invoke(ob);
}
}
Eliminación de código no deseable
A partir de Java 11 Oracle se ha vuelto más decidido en eliminar características que no eran recomendadas. Habitualmente las despreciaba pero ahora se ha decidido directamente en eliminarlas. Por ejemplo ha eliminado Thread.destroy() y Thread.stop(Throwable) . Así que ahora hay que estar más atentos a la compatibilidad con versiones previas al actualizar Java y a los ajustes que debemos implementar en nuestro código.
La lista completa de cambios realizados en Java 11 la puedes observar en este enlace
[http://openjdk.java.net/projects/jdk/11/]