Java Script!= JavaScript。 1つのクラスに5つのjava。 私たちはスクリプトを作成して、永遠に記憶する



今週、JUG.ruグループは発表を発表するでしょう。 何と言うまで。 秘密のプロジェクトに参加することで創造性が目覚めるので、Javaについての別の夜のビデオをご覧ください。



信じられないほどのニュース:今では1時間半の長さではなく、約20分で、見るべきものさえあります。 完全にやや劣り、スクリーンキャストで構成されています。 このビデオのゴミに耐えられず、テキストの復号化を使用したい人は、カット後に大量のテキストをカットする必要がありました。 Welkam、そしてJavaがあなたと共にあるかもしれません。



すぐに12のjavaがリリースされ、多くはまだセメロチカに座っており、アップグレードの場合、特に新しいものや興味深いものは見られないと考えています。 この非常に短い問題では、スクリプト化されたJavaを使用して同僚の生活を地獄に変える方法を学び、いくつかの場所で新しいガジェットを台無しにします。 もちろん、隠蔽者は進歩から救われることはありません。



なぜあなたのアイデアを更新するのですか? 開発者としての生産性を10倍に高める新しい機能、いくつかの新しいショートカットが常に表示されます。 しかし、あなたはそれらについて知りません。 あなたは本当にこのニュースを読んでいますか? あなたが平均的なユーザーであれば、おそらくそうではありません。 あなたは、原則として、ほとんどの時間を気にしないでください。 あなたができるという理由だけで、あなたはアイデアを更新しています。 スキンが美しいため、暗いテーマ、MacBookのタッチバー。 しかし、そのような説明は、「なぜアイデアを買うのか」という答えとして当局の前で失敗することはありません。



代わりに、10月29日、最近ではJetBrainsがIdeaのベータ版で生の行のサポートを固定したと言えます。 アイデアはベータ版で、行はプレビュー版ですが、これは誰にとっても重要ではありません。 12個のjavaを配置するほど頑固な場合は、さらに深刻な問題が発生します。 私は自分で知っています。



実際にどのように見えるか見てみましょう。 これを行うには、何らかのデモ問題を解決してください。 かなり頻繁に何かをスクリプト化する問題があります。 たとえば、コンピューターゲームではこれらはクエストであり、ジェンキンではこれらはビルドスクリプトなどです。 通常、これにはPythonまたはGroovesが使用されますが、ベアJavaを使用してみましょう。 なんで? なぜなら、私たちは3行で、しかもハッキングなしでもできるからです。 素晴らしいアイデアのように聞こえます:-)



見どころ



すべてがgithubにあります。



範囲



次のようなファイルがあると想像してください。



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





アプリケーション全体をコンパイルするときではなく、起動後に文字列として実行する必要があります。 スクリプトのように、つまり。



手動で



まず、すべてを文字列に追い越す必要があります。



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





これらすべての「\ n」プラスとインデントは非常に悲惨に見えます。



以前は、コードをファイルに入れて読み取るだけでした。 これはおそらく良い解決策ですが、常に適切であるとは限りません。 たとえば、あなたは会議の講演者であり、スライドのコードをデモンストレーションします。 上記の構造でさえ、どこかで何かをするコードがあるという実証されていない参照よりもはるかに優れています。 スライドを切り替えるには、時間と視聴者の注意が必要です。 まあなど。 要するに、コードを正確にインラインで必要とする場合、思いつくことができます。



今、生の文字列を使用してゴミを取り除く機会があります。 コードにカーソルを合わせてAltキーを押しながらEnterキーを押します(または、アイデアで実行されているOSのQuck Fixを実行します)。 「生の文字列リテラルに変換」を選択して、この種の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";
      
      





私の意見では、この機能のために、JDK 12をインストールすることはすでに実行する価値があります。



ところで、機能が機能するためには、いくつかのことを行う必要があります。





わからない場合は、その方法、投稿の見出しからのスクリーンキャストをご覧ください。



さて、開始するには、3つの簡単な手順を実行する必要があります。文字列をソースの便利な内部表現に変換し、コンパイルして実行します。



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





「便利な表現」にはSimpleJavaFileObject



クラスがありますが、1つの興味深い機能があります。 それは極めて抽象的です。 つまり、コンパイルされたソースコードが返すキーメソッドは、サブクラス化することを期待して、常に実行をスローします。



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





そのため、相続人を書く必要があります。 元のSimpleJavaFileObject



コンストラクタはコンパイルされたクラスのURIを必要としますが、どこで取得できるのか注意してください。 したがって、ここでは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; }
      
      





それではコンパイルに移りましょう。



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





注:アセンブリには4つのフラグを渡します。そのうち3つは、Ideaのjavac設定でマウスを使用した場合とまったく同じオプションを処方する役割を果たします。



最後に、一時クラスを実行します。



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





var clss = loader.loadClass



Class<?> clss = loader.loadClass



よりも記述しvar clss = loader.loadClass



、新しい変更は導入されないことに注意してください。 var



キーワードはトップ10に登場しました。



また、 clss.newInstance()



Nineから始まるように提案されていることに注意してください。 彼は例外を飲み込みますが、それは悪いことです。 Nineは、最初にgetConstructor



呼び出すことを提案します。これはパラメーター化され、正しい例外をスローします。



また、変数をword class



と呼んでいますが、Javaは誓いませんでした。 宿題:いくつかの方法でこれを行うことができます。どれが最もおもしろいか、なぜかを理解する必要があります。



まあ、一般的には、それですべてです。 動作します。



自動化



Javaの世界には、すべてを1行でコンパイルするライブラリがあるので、批評家はここですべてが黒であると叫ぶでしょう。



OK、見てみましょう。 Googleの上部にあるJOORライブラリのコードは次のとおりです。



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





すべてがうまくいくかのように。 実際、1行で、ただしsaplayerをドラッグする必要がありました。



しかし、ニュアンスがあります。 生の文字列リテラルとして「Hello Habr!」を返してみてください。



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





エラー「(生の文字列リテラルを有効にするには--able-previewを使用してください)」ですべてが即座にクラッシュします。 しかし、すでに有効にしましたか? はい、二人で地獄に。 それをIdeaに含め、JOORはシステムコンパイラでビルドします! 中身を見てみましょう。



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





そして、私たち自身が同じ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);
      
      





また、JOORでは、オプションの代わりに裸のヌルがあります。 内部に渡すことさえできません!



このようなプルリクエストをJOORのGithubに送信することをお勧めします。 自分で手に入らなかったら、あなたはそれをしますよね?



そして、道徳は単純です、オープンソースの贈り物を恐れて。 テキストの小さな壁を書く方が簡単な場合もありますが、それを制御できます。



最も簡単な方法



テキストの壁を書かない方法、および疑わしいライブラリを使用しない方法があります。 Java 9以降では、Javaコマンドを実行できる対話型シェル(Python、Ruby、およびその他のスクリプト言語のシェルに類似)があります。 そしてもちろん、Java自体で書かれており、Javaクラスとして利用可能です。 インスタンスを作成し、必要な割り当てを直接実行することができます。



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





ストリームはJava 8で登場し、今ではどこでも使用されています。 stream()



自分で呼び出す必要はありません。他の人があなたのために呼び出します。 この場合、 variables()



呼び出すと、7人の子供時代の困難な人が行ったように、ArrayListではなく、正確にストリームが返されます。 ストリームの結果はすぐにvar



に注ぐことができます。



ラムダパラメータでもvar



を記述できることに注意してください。 この機能は、Java 11から提供されています。



一般的に、これは非常に重要なクラスです。 さまざまな世代のJavaの多数の機能を使用しており、これらすべてが全体的かつ調和的に見えます。 このようなものは誰でもどこでも使用されると確信しているため、Java 12のコードはJava 7のコードとは視覚的に直接異なります。



まとめると



いくつかの機能を検討しました。





初心者向けの小さな警告。 特別な意味を持たずに実際のアプリケーションでこれを常に行うと、同僚は最初は夢中になり、書いた内容を理解しようとするでしょう。 もちろん、私は新しいJava機能についてではなく、実行時のコンパイルについて話します。



言語としてのJavaについて詳しく知りたい場合は、たとえば、Tagir Valeevのレポートをご覧ください。 あなたは、彼がHabréのJavaハブのトップから来た男だと知っています。 ジョーカーではアンバーについて、またJPointでは有名なパズルなどについて話しました。 そこに、そしてJava言語について、そしてIntelliJ IDEAについて、すべてがそこにあります。 これらはすべてYouTube確認できます。 実際、Tagirのjeから、彼は言語自体について何かを言うことができますが、私はしません、そしてこの投稿は判明しました。 新しいジョーカーとJPointもありますが、これについては後で説明します。



私は道徳的義務、Javaに対する義務を果たしました。 私の側から、弾丸が飛んだ。 そして、あなたはそこにいる、12番目のジャワを持っていない7人で、ここにいてください、あなたはすべて最高の、良い気分と健康です。 ありがとう



All Articles