Java Script! = JavaScript. Cinco javas en una clase. Escribimos para recordar siempre


Esta semana, es probable que el Grupo JUG.ru publique un anuncio. Hasta que yo diga qué. La participación en proyectos secretos despierta la creatividad, así que aquí hay otro video nocturno sobre Java.

Noticias increíbles: ahora no dura una hora y media, sino unos 20 minutos, e incluso hay algo que ver. Un poco menos que completamente, consiste en un screencast. Aquellos que no pueden soportar esta basura de video y les gusta consumir descifrado de texto, tuvieron que cortar mucho texto después del corte. Welkam, y que Java esté contigo.

Pronto se lanzarán 12 Java, y muchos todavía están sentados en Semerochka y creen que en el caso de una actualización no verán nada particularmente nuevo o interesante. En este número súper corto, aprenderemos cómo convertir la vida de nuestros colegas en un infierno con la ayuda de Java con guiones, y en un par de lugares voy a atornillar nuevos dispositivos. Bueno, los oscurantistas, por supuesto, no serán salvados del progreso.

Dime, ¿por qué estás actualizando tu idea? Allí aparecen constantemente nuevas funciones, algunos atajos nuevos, lo que aumenta diez veces su productividad como desarrollador. Pero no sabes sobre ellos. ¿De verdad estás leyendo esta noticia? Si eres un usuario promedio, entonces probablemente no. A ti, en principio, no te importa la mayor parte del tiempo. Estás actualizando la Idea simplemente porque ... puedes. Debido a que las máscaras son hermosas, el tema oscuro, la barra táctil en el MacBook. Pero tal explicación no falla ante las autoridades como la respuesta "por qué comprar la Idea".

En cambio, podemos decir que el 29 de octubre, más recientemente, JetBrains fijó el soporte para líneas sin procesar en la versión beta de Idea . La idea está en beta, las líneas están en la vista previa, pero esto ya no es importante para nadie. Si eres tan terco que pones 12 java, entonces tienes problemas más serios. Lo sé por mi mismo.

Veamos cómo se ve en la práctica. Para hacer esto, intente resolver algún tipo de problema de demostración. Muy a menudo existe el problema de escribir algo. Por ejemplo, en los juegos de computadora son misiones, en jenkins son scripts de compilación, etc. Por lo general, Python o Groove se usan para esto, ¡y tomemos y usemos Java desnudo! Por qué Porque podemos, en tres líneas, e incluso sin hacks. Suena como una gran idea :-)

Donde mirar


Todo está en el github .

Alcance


Imagine que tenemos un archivo como este:

package io.javawatch; public class HelloHabrPrototype { public String get() { return "Hello Habr!"; } }; 

Queremos que se ejecute no al compilar toda la aplicación, sino como una cadena, después del lanzamiento. Como un guión, eso es.

Manualmente


Primero debes adelantar todo en una cadena.

 private static final String SOURCE = "\n" + " package io.javawatch;\n" + " public class HelloHabr {\n" + " public String get() {\n" + " return \"Hello Habr!\";\n" + " }\n" + " };"; public static final String CNAME = "io.javawatch.HelloHabr"; private static String CODE_CACHE_DIR = "C:/temp/codeCache"; 

Todas estas ventajas y sangrías "\ n" se ven extremadamente miserables.

Anteriormente, todo lo que podíamos hacer era poner el código en un archivo y leerlo. Probablemente sea una buena solución, pero no siempre es adecuada. Por ejemplo, usted es un orador en una conferencia y demuestra el código de las diapositivas. Incluso la construcción anterior es mucho mejor que una simple referencia sin fundamento de que tiene un código en algún lugar que hace algo allí. Cambiar diapositivas consume tiempo y atención de la audiencia. Bueno y así sucesivamente. En resumen, en los casos en que necesita el código exactamente en línea, puede encontrarlo.

Ahora tenemos la oportunidad de deshacernos de la basura utilizando cadenas sin procesar. Nos levantamos con el cursor en el código, presionamos Alt + Enter (o lo que sea que se ejecute en su sistema operativo Quck Fix en la Idea). Seleccione "convertir a cadena literal literal" y obtenga esta nyashka:

 private static final String SOURCE = ` package io.javawatch; public class HelloHabr { public String get() { return "Hello Habr!"; } };`; public static final String CNAME = "io.javawatch.HelloHabr"; private static String CODE_CACHE_DIR = "C:/temp/codeCache"; 

En mi opinión, por el bien de esta característica ya vale la pena ejecutar para instalar JDK 12.

Por cierto, para que la característica funcione, deberá hacer varias cosas:

  • Descargue JDK 12 y regístrese en la configuración del proyecto
  • En la configuración global de javac, establezca el indicador --release , bytecode versión 12, indicadores adicionales --enable-preview -Xlint:preview
  • Ahora, en cualquier configuración de ejecución / depuración, debe agregar el indicador VM --enable-preview

Si no lo entiendes, cómo se hace, mira mi screencast desde el encabezado de la publicación, todo está bastante claro allí.

Ahora, para comenzar, debe realizar tres pasos simples: convertir la cadena en una representación interna conveniente de la fuente, compilarla y ejecutarla:

  public static void main(String[] args) throws Exception { /* 1 */ RuntimeSource file = RuntimeSource.create(); //SimpleJavaFileObject /* 2 */ compile(Collections.singletonList(file)); /* 3 */ String result = run(); /* 4 */ /* ??? */ /* 5 */ /* PROFIT! */ System.out.println(result); } 

Hay una clase SimpleJavaFileObject para "representación conveniente", pero tiene una característica interesante. Es crucialmente abstracto. Es decir, su método clave, que la fuente compilada debería devolver, siempre lanza una ejecución con la esperanza de que la subclasemos:

  /** * This implementation always throws {@linkplain * UnsupportedOperationException}. Subclasses can change this * behavior as long as the contract of {@link FileObject} is * obeyed. */ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { throw new UnsupportedOperationException(); } 

Entonces tienes que escribir algo de tu heredero. Tenga en cuenta que el constructor original SimpleJavaFileObject quiere un URI para la clase compilada, pero ¿dónde lo obtenemos? Por lo tanto, sugiero simplemente buildURI la manera más obvia, como aquí en la función buildURI :

  public static class RuntimeSource extends SimpleJavaFileObject { private String contents = null; @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { return contents; } private static RuntimeSource create() throws Exception { return new RuntimeSource(CNAME, SOURCE); } public RuntimeSource(String className, String contents) throws Exception { super(buildURI(className), Kind.SOURCE); this.contents = contents; } public static URI buildURI(String className) { // io.javawatch.HelloHabr -> // string:///io/javawatch/HelloHabr.java URI uri = URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension); System.out.println(uri); return uri; } 

Ahora pasemos a la compilación:

  public static void compile(List<RuntimeSource> files) throws IOException { File ccDir = new File(CODE_CACHE_DIR); if (ccDir.exists()) { FileUtils.deleteDirectory(ccDir); FileUtils.forceMkdir(ccDir); } JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); Logger c = new Logger(); StandardJavaFileManager fileManager = compiler.getStandardFileManager(c, Locale.ENGLISH, null); Iterable options = Arrays.asList("-d", CODE_CACHE_DIR, "--release=12", "--enable-preview", "-Xlint:preview"); JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, c, options, null, files); if (task.call()) { System.out.println("compilation ok"); } } 

Tenga en cuenta: pasamos cuatro banderas para el ensamblaje, tres de las cuales son responsables de prescribir exactamente las mismas opciones que hicimos con el mouse en la configuración de javac en la Idea.

Y finalmente, ejecuta nuestra clase temporal:

  public static String run() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, MalformedURLException { //   File ccDir = new File(CODE_CACHE_DIR); ClassLoader loader = new URLClassLoader(new URL[]{ccDir.toURL()}); var clss = loader.loadClass("io.javawatch.HelloHabr"); // Java 10 //    Object instance = clss.getConstructor().newInstance(); // Java 9 // Object instance = clss.newInstance(); Method thisMethod = clss.getDeclaredMethod("get"); Object result = thisMethod.invoke(instance); return (String) result; } 

Tenga en cuenta que var clss = loader.loadClass de escribir que Class<?> clss = loader.loadClass , y no introduce nuevos vorings. La palabra clave var apareció en el Top Ten.

También tenga en cuenta que clss.newInstance() propone cortar clss.newInstance() a partir de Nine. Se traga las excepciones, lo cual es malo. The Nine sugiere primero llamar a getConstructor , que está parametrizado y arroja las excepciones correctas.

Tenga en cuenta también que llamé a la variable la class palabra, pero Java no juró. Tarea: puede hacer esto de varias maneras, necesita comprender cuál es la más interesante y por qué.

Bueno, en general, eso es todo. Funciona

Automatización


Aquí el crítico exclamará, todo está en negro aquí, porque hay bibliotecas en el mundo de Java que compilan todo para usted en una línea.

OK, echemos un vistazo. Aquí está el código en la biblioteca JOOR, ubicada en la parte superior de Google:

 package io.javawatch; import org.joor.Reflect; import java.util.function.Supplier; public class Automatic { public static void main(String[] args) { Supplier<String> supplier = Reflect.compile( "io.javawatch.HelloHabr", ` package io.javawatch; public class HelloHabr implements java.util.function.Supplier<String> { public String get() { return "Hello Habr!"; } };` ).create().get(); System.out.println(supplier.get()); } } 

Como si todo estuviera bien. De hecho, en una línea, excepto que tuve que arrastrar el saplayer.

Pero hay un matiz. Intenta devolver "¡Hola Habr!" como cadena literal literal:

 public String get() { return ``Hello Habr!``; } 

Todo se bloqueará instantáneamente con el error "(use --able-preview para habilitar los literales de cadena sin formato)". ¿Pero ya lo hemos encendido? Sí, al diablo con dos. ¡Lo incluimos en la Idea, y JOOR lo construye con un compilador del sistema! Echemos un vistazo a lo que hay dentro:

 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); ompiler.getTask(out, fileManager, null, null, null, files).call(); 

¿Y qué hay de nosotros cuando nosotros mismos llamamos al mismo JavaCompiler?

  Iterable options = Arrays.asList("-d", CODE_CACHE_DIR, "--release=12", "--enable-preview", "-Xlint:preview"); JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, c, options, null, files); 

Y en JOOR solo hay un nulo en lugar de opciones. ¡Ni siquiera se pueden pasar adentro!

Probablemente sea una buena idea enviarles una solicitud de extracción a Github en JOOR. Si no voy a hacerlo yo mismo, lo haces, ¿eh?

Y la moraleja es simple, tenga miedo de los regalos de código abierto. A veces es más fácil escribir un pequeño muro de texto, pero tener control sobre él.

La manera más fácil


Hay una manera de no escribir un muro de texto y de no usar bibliotecas sospechosas. Comenzando con Java 9, tenemos un shell interactivo (similar al de Python, Ruby y otros lenguajes de secuencias de comandos) que puede ejecutar comandos Java. Y, por supuesto, está escrito en Java y está disponible como una clase Java. Puede crear una instancia y simplemente realizar la asignación necesaria directamente:

 public class Shell { public static void main(String[] args) { var jShell = JShell.create(); //Java 9 jShell.eval("String result;"); jShell.eval(`result = "Hello Habr!";`); //Java 12 var result = jShell.variables() //Streams: Java 8, var: Java 10 .filter((@Nullable var v) -> v.name().equals("result")) //var+lambda: Java 11 .findAny() .get(); System.out.println(jShell.varValue(result)); } } 

Las secuencias aparecieron en Java 8, y ahora se usan en todas partes, y ni siquiera necesita llamar a stream() usted mismo, otros lo llamarán por usted. En este caso, las variables() llamada variables() devuelven exactamente la secuencia, no la ArrayList, como habría hecho alguien de una infancia difícil. El resultado de la corriente se puede verter inmediatamente en la var .

Tenga en cuenta que ahora puede escribir var también en los parámetros lambda. Esta característica ha estado con nosotros desde Java 11.

En general, esta es una clase muy significativa. Utiliza un montón de características de diferentes generaciones de Java, y todo esto se ve de manera integral y armoniosa. Estoy seguro de que tales cosas serán utilizadas por todos y en todas partes, por lo que el código en Java 12 será visualmente diferente de lo que teníamos en Java 7.

Para resumir


Observamos algunas características:

  • 8: Stream (para aquellos en el tanque)
  • 9: JShell y nuevos métodos obsoletos
  • 10: palabra clave var
  • 11: desarrollo de Var para parámetros lambda
  • 12: Raw String Literals y su soporte en IntelliJ IDEA

Una pequeña advertencia para principiantes. Si constantemente haces esto en aplicaciones reales sin ningún significado especial, tus colegas se volverán locos al principio, tratando de entender lo que escribiste, y luego pueden golpearte muy dolorosamente. Y no estoy hablando de nuevas características de Java ahora, sino de la compilación en tiempo de ejecución, por supuesto.

Si desea obtener más información sobre Java como lenguaje, debería, por ejemplo, consultar los informes de Tagir Valeev. Lo conoces como un tipo desde la parte superior del centro de Java en Habré, lany . En Joker habló sobre Amber , y en JPoint, sus famosos acertijos , y así sucesivamente. Allí, y sobre el lenguaje Java, y sobre IntelliJ IDEA, todo está ahí. Todo esto se puede encontrar en YouTube . En realidad, por celos de Tagir, que puede decir algo sobre el lenguaje en sí, pero yo no, y esta publicación ha resultado. También habrá nuevos comodines y JPoint, pero discutiremos esto más adelante.

Cumplí mi deber moral, un deber con Java. De mi lado, las balas salieron volando. Y usted allí, en el siete, que no tiene el duodécimo Java, quédese aquí, todo lo mejor, buen humor y salud. Gracias

Source: https://habr.com/ru/post/es429670/


All Articles