Programování

Co REPL znamená pro Javu

Možná jste vývojář Clojure nebo Scala, nebo jste v minulosti spolupracovali s LISP. Pokud ano, je velká šance, že jste použili REPL jako součást své každodenní rutiny. REPL, nebo read-eval-print-loop, je rozhraní prostředí, které načte každý řádek vstupu, vyhodnotí tento řádek a poté vytiskne výsledek. Okamžitá zpětná vazba, hezké!

Když používáte REPL, píšete kód interaktivně a neprodleně jej spustíte. Vydání Java 9 v roce 2016 přinese plně funkční prostředí REPL s názvem JShell (s kódovým označením Kulla). Tento článek poskytuje přehled Java REPL a pojednává o některých možnostech, jak byste jej mohli použít ve svém programování v Javě - ano, vy!

Počkejte, Java již nemá REPL?

Určitě zavedený jazyk, jako je Java, musí mít REPL! Vlastně ne všechny jazyky je mají a Java je jedním z těch, kterým to chybělo. Je pravděpodobné, že s větším obřadem a tempem než většina jazyků je Java jedním z jazyků, jejichž vývojáři si to nejvíce zasloužili. Java má na chvíli něco trochu podobného REPL v podobě Java BeanShell, ale tento projekt nikdy nebyl plně vybavený REPL na stejné úrovni jako v jiných jazycích. Byla to jen podmnožina úplné syntaxe jazyka Java.

REPL snižuje obrat

Zkrácení doby obratu a zpětné vazby co nejvíce je neuvěřitelně důležité pro zdravý rozum vývojáře. REPL je skvělý nástroj pro vývojáře, kteří chtějí dosáhnout právě toho. Vývojáři jsou nejproduktivnější, když mohou okamžitě vidět výsledky své práce. Díky Java REPL budou vývojáři schopni psát kód, spouštět tento kód a poté pokračovat ve vývoji svého kódu za běhu, aniž by museli opouštět, aby mohli spustit sestavení atd. Zatímco mnoho systémů využívajících Javu překračuje složitost toho, co by bylo možné zpracovat interaktivním REPL, pouhá přítomnost REPL v JDK znamená, že někdo někde najde úžasný případ použití za okamžik. Skutečnost, že JShell vystavuje API, v podstatě zajišťuje, že vývojáři IDE budou integrovat tento REPL do nástrojů, které používáme k psaní kódu. Počkejte, až bude Java REPL součástí každého IDE!

Začínáme s JShell

Je důležité si uvědomit, že používání vývojového REPL, Project Kulla, není pro slabé povahy. Kulla, aka JShell v době psaní není součástí balíčku náhledu JDK 9, takže budete muset klonovat projekt Mercurial, kompilovat JDK a kompilovat JShell sami. Vyhraďte si na tento proces hodinu, zvláště pokud obvykle neházíte zdrojový kód JDK. Budete muset deaktivovat varování jako chyby, a pokud stavíte na OSX, ujistěte se, že jste nainstalovali XCode společně s XQuartz pro knihovnu freetype. Podle pokynů níže nainstalujte a spusťte Project Kulla ve vývojovém prostředí Java.

1. Nainstalujte Java 9

Chcete-li spustit JShell, musíte si stáhnout a nainstalovat nejnovější verzi náhledu předčasného přístupu pro Javu 9. Jakmile si stáhnete Javu 9, nastavte si JAVA_HOME proměnná prostředí a spuštění java - verze pro ověření instalace. To může být bolest, zejména na OSX, takže stojí za to ji dvakrát zkontrolovat!

2. Nainstalujte Mercurial a Project Kulla

Project Kulla je projekt OpenJDK, takže k jeho kompilaci budete muset naklonovat úložiště Mercurial.

Dále naklonujete úložiště Kulla:

 klon hg //hg.openjdk.java.net/kulla/dev kulla 

Potom nakonfigurujete sestavení:

 cd kulla bash ./configure --disable-warnings-as-errors vytvářejí obrázky 

3. Zkompilujte a spusťte REPL

Tady je kód pro kompilaci REPL:

 cd langtools / repl; bash ./scripts/compile.sh 

A tady je kód pro jeho spuštění:

 bash ./scripts/run.sh 

Jak jsem poznamenal, funkce REPL v Javě ještě není připravena k obecné spotřebě, ale stále ji můžeme vzít na časnou testovací jízdu!

Děláš matematiku

Počáteční příklad toho, co může JShell dělat, pojďme vyhodnotit některé jednoduché výrazy pomocí java.lang.Math:

Výpis 1. Vyhodnocování matematických výrazů pomocí REPL

 $ bash ./scripts/run.sh | Vítejte v JShell - verze 0.710 | Typ / nápověda pro pomoc -> Math.sqrt (144.0f); | Hodnota výrazu je: 12,0 | přiřazeno dočasné proměnné $ 1 typu double -> $ 1 + 100; | Hodnota výrazu je: 112,0 | přiřazeno dočasné proměnné $ 2 typu double -> / vars | double $ 1 = 12,0 | double $ 2 = 112,0 -> double val = Math.sqrt (9000); | Přidána proměnná val typu double s počáteční hodnotou 94,86832980505137 

Tady vyhodnocujeme výrazy, nacházíme druhou odmocninu čísla a potom přidáváme dvě čísla dohromady. Toto není nejsložitější kód, ale měli byste si uvědomit, že / vars příkaz nám dává možnost vypsat proměnné vytvořené v relaci JShell. Na hodnoty nepřiřazených výrazů můžeme odkazovat pomocí znaku dolaru ($). Nakonec můžeme vytvořit novou proměnnou a přiřadit jí hodnotu.

Definujte metodu

Nyní je to zajímavější. V tomto příkladu definujeme metodu pro výpočet Fibonacciho posloupnosti. Po definování metody zkontrolujeme, které metody jsou definovány pomocí /metody příkaz. Nakonec provedeme fragment kódu, který provede smyčku v poli a vytiskne prvních několik čísel v pořadí.

Výpis 2. Vypočítejte Fibonacciho posloupnost

 $ bash ./scripts/run.sh | Vítejte v JShell - verze 0.710 | Typ / nápověda pro pomoc -> dlouhý fibonacci (dlouhé číslo) >> if ((number == 0) | Přidaná metoda fibonacci (dlouhá) -> / metody | fibonacci (dlouhá) dlouhá -> fibonacci (12) | Hodnota výrazu je : 144 | přiřazeno k dočasné proměnné $ 1 typu long -> int [] pole = {1,2,3,4,5,6,7,8}; | Přidáno proměnné pole typu int [] s počáteční hodnotou [I @ 4f4a7090 -> for (long i: array) {System.out.println (fibonacci (i));} 1 1 2 3 5 8 13 21 

Ve stejné relaci JShell můžu předefinovat definici metody Fibonacci a provést stejný kód. Tímto způsobem můžete pomocí REPL rychle spouštět, upravovat a testovat nové algoritmy.

Výpis 3. REPL pro opakované použití

 -> dlouhý fibonacci (dlouhé číslo) {>> návrat 1; >>} | Upravená metoda fibonacci (long) -> for (long i: array) {System.out.println (fibonacci (i)); } 1 1 1 1 1 1 1 

Definujte třídu

Následující příklad ukazuje, jak definovat celou třídu v JShellu a poté odkazovat na tuto třídu ve výrazu - vše bez opuštění REPL. Schopnost dynamicky vytvářet a testovat kód vás osvobodí od rychlého experimentování a iterace s novým kódem.

Výpis 4. Definice dynamické třídy

 MacOSX: repl tobrien $ bash ./scripts/run.sh | Vítejte v JShell - verze 0.710 | Typ / nápověda pro pomoc -> třída Osoba {>> public Název řetězce; >> veřejný věk; >> public Popis řetězce; >> >> public Osoba (jméno řetězce, věk, popis řetězce) {>> this.name = jméno; >> this.age = věk; >> this.description = description; >>} >> >> public String toString () {>> vrátit this.name; >>} >>} | Přidána třída Osoba -> Osoba p1 = nová Osoba („Tom“, 4, „Má rád Spidermana“); | Přidána proměnná p1 typu Osoba s počáteční hodnotou Tom -> / vars | Osoba p1 = Tom 

I když je schopnost dynamicky definovat třídy silná, není to tak, jako by se vývojáři dožadovali psaní velkých víceřádkových definic v interaktivním prostředí. To je místo, kde koncept Dějiny a chystáte se načíst a uložit stav REPL začíná být důležité. S /Dějiny příkaz můžete uvést všechny příkazy a výrazy vyhodnocené v REPL.

Výpis 5. Poznejte svoji / historii

 -> / historie třída Osoba {veřejné Název řetězce; veřejný věk; veřejný popis řetězce; public Osoba (název řetězce, stáří, popis řetězce) {this.name = name; this.age = věk; this.description = description; } public String toString () {return this.name; }} Osoba p1 = nová osoba ("Tom", 4, "má rád Spidermana"); Osoba p2 = nová osoba ("Zach", 10, "dobrý v matematice"); / vars p1 p2 / historie 

Poté můžete uložit svou historii REPL do souboru a pojmenovat jej, aby jej bylo možné později znovu načíst. Zde je příklad:

 -> / save output.repl -> / reset | Resetování stavu. -> / vars -> / otevřít výstup.repl -> / vars | Osoba p1 = Tom | Osoba p2 = Zach 

The /Uložit příkaz uloží historii REPL do souboru, / reset příkaz resetuje stav REPL a /otevřeno příkaz načte do souboru a provede stavy proti REPL. Funkce uložení a otevření vám umožňují nastavit velmi složité skripty REPL, které můžete použít ke konfiguraci různých scénářů REPL.

Úpravy definice třídy za běhu

JShell také umožňuje nastavit spouštěcí definiční soubor a automaticky načítat definice. Můžete skákat kolem své historie REPL a upravovat pojmenované zdrojové položky. Například kdybych chtěl upravit definici Osoba třídy z tohoto příkladu bych mohl použít /seznam a /Upravit příkazy.

Výpis 6. Úprava osoby

 -> / l 1: třída Osoba {veřejné Název řetězce; veřejný věk; veřejný popis řetězce; public Osoba (název řetězce, stáří, popis řetězce) {this.name = name; this.age = věk; this.description = description; } public String toString () {return this.name; }} 2: Osoba p1 = nová osoba ("Tom", 4, "má rád Spidermana"); 3: Osoba p2 = nová osoba („Zach“, 10, „dobrý v matematice“); 4: p1 5: p2 -> / upravit 1 

Spuštění tohoto /Upravit příkaz načte jednoduchý editor, kde mohu změnit definici třídy a okamžitě aktualizovat třídu.

Co je velký problém?

Promluvte si s programátorem Clojure nebo LISP o tom, jak se každý den vyvíjejí, a uvidíte, že kódují v rámci REPL. Nepíšou skripty a poté je spouští tolik času, kolik tráví většinu svého času vývojem interaktivních změn kódu. Pokud máte několik hodin času nazbyt, zeptejte se vývojáře Scala nebo Clojure na jejich REPL. Takhle fungují.

Java je jiný jazyk než Scala nebo Clojure. Vývojáři Java netráví dny zaměřené na jednotlivé řádky LISP, které by mohly obsahovat celé programové struktury v několika prohlášeních. Většina programů Java vyžaduje, aby nastavení fungovalo správně, a zatímco nedávné změny jazyka snížily počet řádků systémů napsaných v Javě, stále měříme složitost našich systémů v tisících řádků kódu. Jednoduché Osoba výše uvedený příklad není užitečný kód a nejužitečnější kód v Javě s sebou nese složitost, která bude obtížné zapadnout do programovacího prostředí založeného na REPL.

Vývojáři Scala a Clojure praktikují něco takového Programování clojure autor Chas Emerick nazývá „iterativní vývoj“, který nezávisí na souborovém pracovním postupu. Vývojáři Java jsou závislí na desítkách knihoven, složitých hierarchií závislostí a kontejnerů jako Tomcat nebo TomEE. Z tohoto důvodu nepředpovídám, že programování orientované na REPL předběhne tradiční vývoj Javy v IDE. Místo toho vidím, že Java REPL poskytuje několik odlišných výhod a příležitostí.

1. Učení jazyka Java: Protože programy Java vyžadují tolik nastavení, může být pro vývojáře, kteří se učí jazyk, náročné porozumět syntaxi rychle. REPL prostředí Java 9 se stane primárním způsobem, jak noví vývojáři zvládnou základní syntaxi.

2. Experimentování s novými knihovnami: Java má stovky užitečných open source knihoven pro vše od manipulace s datem a časem až po matematické knihovny. Bez REPL, kdykoli chce vývojář porozumět nové knihovně, nevyhnutelně vytvoří několik výměnných tříd s obvyklými "public static void main„Obřad. S REPL můžete jen vystřelit a hrát bez této režie.

3. Rychlé prototypování: To je blíže tomu, jak většina vývojářů Clojure a Scala iterativně pracuje, ale pokud pracujete na cíleném problému, REPL usnadňuje rychlou iteraci změn tříd a algoritmů. S REPL nebudete muset čekat na dokončení sestavení; můžete rychle vylepšit definici třídy, resetovat REPL a zkusit to znovu.

4. Integrace s build systémy: Gradle poskytuje interaktivní režim „shellu“ a komunita Mavenů podobné nástroje v minulosti dodávala. Vývojáři, kteří chtějí snížit složitost sestavení, by mohli prozkoumat použití REPL jako nástroje pro orchestraci jiných systémů.

Moje poslední 2c

Vidím Java REPL jako něco, co v příštích několika letech začne ovlivňovat každodenní vývoj pro ty, kteří upgradují na Java 9. Také si myslím, že komunita Java bude potřebovat čas, aby se plně přizpůsobila nový styl vývoje a porozumět výzvám i příležitostem, které REPL poskytuje. Neočekávám, že většina vývojářů Java přejde na vývoj orientovaný na REPL jako jejich programovací bratranci Clojure, ale myslím si, že uvidíme, jak REPL ovlivní způsob, jakým se noví vývojáři učí Javu. Jelikož se noví vývojáři Java poprvé setkávají s Javou v rámci REPL, není pochyb o tom, že začne ovlivňovat to, jak budujeme a prototypujeme systémy založené na Javě.

Tento příběh „Co REPL znamená pro Javu“ původně publikoval JavaWorld.