Java Script! = JavaScript. Fünf Javas in einer Klasse. Wir schreiben, damit wir uns für immer erinnern


Diese Woche wird die JUG.ru-Gruppe voraussichtlich eine Ankündigung veröffentlichen. Bis ich was sage. Die Teilnahme an geheimen Projekten weckt die Kreativität. Hier ist ein weiteres Nachtvideo über Java.

Unglaubliche Neuigkeiten: Jetzt sind es nicht mehr anderthalb Stunden, sondern ungefähr 20 Minuten, und es gibt sogar etwas zu sehen. Etwas weniger als vollständig besteht es aus einem Screencast. Diejenigen, die diesen Video-Müll nicht ausstehen können und gerne Text entschlüsseln, mussten nach dem Schneiden viel Text schneiden. Welkam, und möge Java mit Ihnen sein.

Bald werden 12 Java veröffentlicht, und viele sitzen immer noch auf Semerochka und glauben, dass sie bei einem Upgrade nichts besonders Neues oder Interessantes sehen werden. In dieser superkurzen Ausgabe lernen wir, wie wir mit Hilfe von Java-Skripten das Leben unserer Kollegen in die Hölle verwandeln können, und an einigen Stellen werde ich neue Gadgets schrauben. Nun, Obskurantisten werden natürlich nicht vor dem Fortschritt gerettet.

Sag mir, warum aktualisierst du deine Idee? Dort erscheinen ständig neue Funktionen, einige neue Verknüpfungen, die Ihre Produktivität als Entwickler zehnmal steigern. Aber Sie wissen nichts über sie. Lesen Sie diese Nachrichten wirklich? Wenn Sie ein durchschnittlicher Benutzer sind, dann wahrscheinlich nicht. Im Prinzip ist es Ihnen die meiste Zeit egal. Sie aktualisieren die Idee einfach, weil ... Sie können. Weil die Skins wunderschön sind, das dunkle Thema, die Touchbar auf dem MacBook. Eine solche Erklärung scheitert jedoch nicht vor den Behörden als Antwort „Warum die Idee kaufen?“.

Stattdessen können wir sagen, dass JetBrains am 29. Oktober in jüngerer Zeit die Unterstützung für Rohlinien in der Beta-Version von Idea eingestellt hat . Die Idee ist in der Beta, die Zeilen sind in der Vorschau, aber das ist für niemanden mehr wichtig. Wenn Sie so stur sind, dass Sie 12 Java setzen, dann haben Sie ernstere Probleme. Ich weiß es für mich.

Mal sehen, wie es in der Praxis aussieht. Versuchen Sie dazu, ein Demonstrationsproblem zu lösen. Sehr oft gibt es das Problem, etwas zu schreiben. In Computerspielen handelt es sich beispielsweise um Quests, in Jenkins um Build-Skripte usw. Normalerweise wird dafür Python oder Groove verwendet, und wir nehmen nacktes Java! Warum, warum? Weil wir in drei Zeilen und sogar ohne Hacks können. Klingt nach einer großartigen Idee :-)

Wo zu sehen


Alles ist auf dem Github .

Geltungsbereich


Stellen Sie sich vor, wir haben eine Datei wie diese:

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

Wir möchten, dass es nicht beim Kompilieren der gesamten Anwendung ausgeführt wird, sondern als Zeichenfolge - nach dem Start. Das heißt wie ein Skript.

Manuell


Zuerst müssen Sie alles in eine Zeichenfolge überholen.

 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"; 

Alle diese "\ n" Pluspunkte und Einrückungen sehen äußerst miserabel aus.

Bisher konnten wir den Code nur in eine Datei einfügen und lesen. Dies ist wahrscheinlich eine gute Lösung, aber nicht immer geeignet. Sie sind beispielsweise Redner auf einer Konferenz und demonstrieren Code von Folien. Selbst die obige Konstruktion ist viel besser als nur eine unbegründete Referenz, dass Sie irgendwo einen Code haben, der dort etwas tut. Das Wechseln der Folien kostet Zeit und Aufmerksamkeit des Publikums. Gut und so weiter. Kurz gesagt, wenn Sie den Code genau inline benötigen, können Sie sich etwas einfallen lassen.

Jetzt haben wir die Möglichkeit, den Müll mit rohen Strings loszuwerden. Wir stehen mit dem Cursor auf dem Code auf, drücken Alt + Eingabetaste (oder was auch immer auf Ihrem Betriebssystem läuft Quck Fix in der Idee). Wählen Sie "In rohes String-Literal konvertieren" und erhalten Sie dieses 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"; 

Meiner Meinung nach lohnt es sich aus diesem Grund bereits, JDK 12 zu installieren.

Übrigens müssen Sie verschiedene Dinge tun, damit die Funktion funktioniert:

  • Laden Sie JDK 12 herunter und registrieren Sie sich in den Projekteinstellungen
  • Setzen --release in den globalen Javac-Einstellungen das Flag --release , Bytecode Version 12, zusätzliche Flags --enable-preview -Xlint:preview
  • Jetzt müssen Sie in jeder Run / Debug-Konfiguration das VM-Flag --enable-preview hinzufügen

Wenn Sie es nicht verstehen, wie es gemacht wird, sehen Sie sich meinen Screencast aus der Post-Überschrift an. Dort ist alles ziemlich klar.

Zunächst müssen Sie drei einfache Schritte ausführen: Verwandeln Sie die Zeichenfolge in eine praktische interne Darstellung der Quelle, kompilieren Sie sie und führen Sie Folgendes aus:

  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); } 

Es gibt eine SimpleJavaFileObject Klasse für die „bequeme Darstellung“, die jedoch eine interessante Funktion aufweist. Es ist kritisch abstrakt. Das heißt, seine Schlüsselmethode, die die kompilierte Quelle zurückgeben sollte, löst immer eine Ausführung in der Hoffnung aus, dass wir sie in Unterklassen unterteilen:

  /** * 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(); } 

Sie müssen also einen Teil Ihres Erben schreiben. Beachten Sie, dass der ursprüngliche SimpleJavaFileObject Konstruktor einen URI für die kompilierte Klasse wünscht, aber woher bekommen wir ihn? Daher schlage ich vor, es nur auf die offensichtlichste Weise buildURI , wie hier in der buildURI Funktion:

  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; } 

Fahren wir nun mit der Zusammenstellung fort:

  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"); } } 

Bitte beachten Sie: Wir übergeben vier Flags für die Montage, von denen drei dafür verantwortlich sind, genau die gleichen Optionen vorzuschreiben, die wir mit der Maus in den Javac-Einstellungen in der Idee gemacht haben.

Und zum Schluss führen Sie unsere temporäre Klasse durch:

  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; } 

Bitte beachten Sie, dass var clss = loader.loadClass zu schreiben ist als Class<?> clss = loader.loadClass und keine neuen Vorings einführt. Das Schlüsselwort var in den Top Ten angezeigt.

Beachten Sie auch, dass clss.newInstance() ab Nine abgeschnitten werden soll. Er schluckt Ausnahmen, was schlecht ist. The Nine schlägt vor, zuerst getConstructor , der parametrisiert ist und die richtigen Ausnahmen getConstructor .

Bitte beachten Sie auch, dass ich die Variable als Wortklasse bezeichnet habe, Java jedoch nicht geschworen hat. Hausaufgaben: Sie können dies auf verschiedene Arten tun. Sie müssen verstehen, welche am interessantesten ist und warum.

Nun, im Allgemeinen ist das alles. Es funktioniert.

Automatisierung


Hier wird der Kritiker ausrufen, hier ist alles schwarz, weil es in der Java-Welt Bibliotheken gibt, die alles für Sie in einer Zeile zusammenstellen.

OK, lass uns einen Blick darauf werfen. Hier ist der Code in der JOOR-Bibliothek oben in 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()); } } 

Als ob alles in Ordnung wäre. In der Tat in einer Zeile, außer dass ich den Saplayer ziehen musste.

Aber es gibt eine Nuance. Versuchen Sie, "Hallo Habr!" wie rohes String-Literal:

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

Alles wird sofort mit dem Fehler "(verwenden Sie --able-Preview, um rohe String-Literale zu aktivieren)" abstürzen. Aber haben wir es schon eingeschaltet? Ja, zur Hölle mit zwei. Wir haben es in die Idee aufgenommen und JOOR erstellt es mit einem System-Compiler! Werfen wir einen Blick darauf, was drin ist:

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

Und was ist mit uns, als wir selbst denselben JavaCompiler aufgerufen haben?

  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); 

Und in JOOR gibt es nur eine bloße Null anstelle von Optionen. Sie können nicht einmal hineingelassen werden!

Es ist wahrscheinlich eine gute Idee, ihnen eine solche Pull-Anfrage an Github in JOOR zu senden. Wenn ich es nicht selbst mache, machst du es, oder?

Und die Moral ist einfach, fürchte dich vor Open-Source-Geschenken. Manchmal ist es einfacher, eine kleine Textwand zu schreiben, aber die Kontrolle darüber zu haben.

Einfachster Weg


Es gibt eine Möglichkeit, keine Textwand zu schreiben und keine verdächtigen Bibliotheken zu verwenden. Ab Java 9 haben wir eine interaktive Shell (ähnlich der in Python, Ruby und anderen Skriptsprachen), die Java-Befehle ausführen kann. Und natürlich ist es in Java selbst geschrieben und als Java-Klasse verfügbar. Sie können eine Instanz davon erstellen und die erforderliche Zuordnung einfach direkt ausführen:

 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)); } } 

Streams wurden in Java 8 angezeigt und werden jetzt überall verwendet. Sie müssen stream() nicht einmal selbst aufrufen, andere rufen es für Sie auf. In diesem Fall gibt der Aufruf von variables() genau den Stream zurück, nicht die ArrayList, wie es jemand aus einer schwierigen Kindheit getan hätte. Das Ergebnis des Stroms kann sofort in var gegossen werden.

Beachten Sie, dass Sie var jetzt auch in Lambda-Parameter schreiben können. Diese Funktion ist seit Java 11 bei uns.

Im Allgemeinen ist dies eine sehr bedeutende Klasse. Es verwendet eine Reihe von Funktionen aus verschiedenen Generationen von Java, und all dies sieht ganzheitlich und harmonisch aus. Ich bin sicher, dass solche Dinge von jedem und überall verwendet werden, daher unterscheidet sich der Code in Java 12 visuell direkt von dem in Java 7.

Zusammenfassend


Wir haben uns einige Funktionen angesehen:

  • 8: Stream (für diejenigen im Tank)
  • 9: JShell und neue veraltete Methoden
  • 10: Schlüsselwort var
  • 11: Var-Entwicklung für Lambda-Parameter
  • 12: Raw String Literals und ihre Unterstützung in IntelliJ IDEA

Eine kleine Warnung für Anfänger. Wenn Sie dies in realen Anwendungen ohne besondere Bedeutung ständig tun, werden Ihre Kollegen zuerst verrückt und versuchen zu verstehen, was Sie geschrieben haben, und dann können sie Sie sehr schmerzhaft schlagen. Und ich spreche jetzt nicht über neue Java-Funktionen, sondern natürlich über die Kompilierung zur Laufzeit.

Wenn Sie mehr über Java als Sprache erfahren möchten, sollten Sie sich beispielsweise die Berichte von Tagir Valeev ansehen. Sie kennen ihn als einen Typen von der Spitze des Java-Hubs in Habré, Lany . Bei Joker sprach er über Amber und bei JPoint über seine berühmten Rätsel und so weiter und so fort. Dort und über die Java-Sprache und über IntelliJ IDEA ist alles da. All dies finden Sie auf YouTube . Eigentlich aus Eifersucht auf Tagir, der etwas über die Sprache selbst sagen kann, aber ich nicht und dieser Beitrag hat sich herausgestellt. Es wird auch neue Joker und JPoint geben, aber wir werden dies später diskutieren.

Ich habe meine moralische Pflicht erfüllt, eine Pflicht gegenüber Java. Von meiner Seite flogen die Kugeln heraus. Und Sie dort, auf den sieben, die nicht das zwölfte Java haben, bleiben hier, Sie alles Gute, gute Laune und Gesundheit. Vielen Dank.

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


All Articles