Programmering

Hvad REPL betyder for Java

Måske er du en Clojure- eller Scala-udvikler i et skab, eller måske har du tidligere arbejdet med LISP. I så fald er der en god chance for, at du har brugt en REPL som en del af din daglige rutine. REPL, eller read-eval-print-loop, er en shell-interface, der læser hver inputlinje, evaluerer linjen og derefter udskriver resultatet. Øjeblikkelig feedback, dejligt!

Når du bruger en REPL, skriver du kode interaktivt og udfører den uden forsinkelse. Udgivelsen af ​​Java 9 i 2016 vil levere et fuldt funktionelt REPL-miljø ved navn JShell (kode med navnet Kulla). Denne artikel giver et overblik over Java REPL og diskuterer nogle muligheder for, hvordan du kan bruge det i din Java-programmering - ja, du!

Vent, Java har ikke allerede en REPL?

Et etableret sprog som Java skal helt sikkert have en REPL! Nå, faktisk har ikke alle sprog dem, og Java er et af dem, der har manglet det. Formentlig, med mere ceremoni og kedelplade end de fleste sprog, er Java et af de sprog, hvis udviklere har fortjent det mest. Java har haft noget lidt REPL-lignende i et stykke tid i form af Java BeanShell, men dette projekt var aldrig en fuldt udstyret REPL på niveau med andre sprog. Det var bare en delmængde af den fulde Java-sprogsyntaks.

REPL reducerer turnaround

At forkorte leveringstiden og feedback-løkker så meget som muligt er utroligt vigtigt for en udviklers sundhed. En REPL er et godt værktøj til udviklere, der ønsker at opnå netop det. Udviklere er mest produktive, når de straks kan se resultaterne af deres arbejde. Med en Java REPL vil udviklere være i stand til at skrive kode, udføre denne kode og derefter fortsætte med at udvikle deres kode on-the-fly uden at skulle afslutte for at køre en build og så videre. Mens mange af de systemer, der bruger Java, ligger ud over kompleksiteten af, hvad der kunne håndteres af en interaktiv REPL, betyder den blotte tilstedeværelse af en REPL i JDK, at nogen et eller andet sted vil finde en fantastisk brugssag for det på ingen tid. Det faktum, at JShell udsætter en API, dybest set sikrer, at IDE-udviklere vil integrere denne REPL i de værktøjer, vi bruger til at skrive kode. Vent bare til Java REPL er en del af enhver IDE!

Kom godt i gang med JShell

Det er vigtigt at indse, at brug af REPL under udvikling, Project Kulla, ikke er for svag af hjertet. Kulla, aka JShell, er ikke en del af JDK 9-preview-pakken i skrivende stund, så du bliver nødt til at klone et Mercurial-projekt, kompilere JDK og kompilere JShell selv. Afsæt en time til denne proces, især hvis du normalt ikke kaster JDK-kildekoden rundt. Du bliver nødt til at deaktivere advarsler som fejl, og hvis du bygger videre på OSX, skal du sørge for at have installeret XCode sammen med XQuartz til freetype-biblioteket. Følg instruktionerne nedenfor for at installere og køre Project Kulla i dit Java-udviklingsmiljø.

1. Installer Java 9

For at køre JShell skal du downloade og installere den seneste forhåndsvisning af forhåndsvisning af Java til Java 9. Når du har downloadet Java 9, skal du indstille din JAVA_HOME miljøvariabel og kør java –version for at bekræfte din installation. Dette kan være en smerte, især på OSX, så det er værd at dobbelttjekke!

2. Installer Mercurial og Project Kulla

Project Kulla er et OpenJDK-projekt, så du bliver nødt til at klone Mercurial-arkivet for at kompilere det.

Dernæst kloner du Kulla-arkivet:

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

Derefter konfigurerer du build:

 cd kulla bash ./configure - deaktiver-advarsler-som-fejl gør billeder 

3. Kompilér og kør REPL

Her er koden til kompilering af REPL:

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

Og her er koden til at køre den:

 bash ./scripts/run.sh 

Som jeg bemærkede, er Java's REPL-funktion endnu ikke klar til almindeligt forbrug, men vi kan stadig tage den til et tidligt testdrev!

Du laver matematikken

For et indledende eksempel på, hvad JShell kan gøre, lad os evaluere nogle enkle udtryk ved hjælp af java.lang.Math:

Liste 1. Evaluering af matematiske udtryk med REPL

 $ bash ./scripts/run.sh | Velkommen til JShell - Version 0.710 | Skriv / hjælp til hjælp -> Math.sqrt (144.0f); | Ekspressionsværdi er: 12,0 | tildelt den midlertidige variabel $ 1 af typen dobbelt -> $ 1 + 100; | Ekspressionsværdi er: 112,0 | tildelt den midlertidige variabel $ 2 af typen dobbelt -> / vars | dobbelt $ 1 = 12,0 | dobbelt $ 2 = 112.0 -> dobbelt val = Math.sqrt (9000); | Tilføjet variabel værdi af typen dobbelt med startværdi 94.86832980505137 

Her evaluerer vi udtryk, finder kvadratroden af ​​et tal og tilføjer derefter to tal sammen. Dette er ikke den mest komplekse kode, men du skal bemærke, at / vars kommando giver os muligheden for at liste de variabler, der er oprettet i JShell-sessionen. Vi kan henvise til værdier for ikke-tildelte udtryk ved hjælp af en dollartegn ($) notation. Endelig kan vi oprette en ny variabel og tildele den en værdi.

Definer en metode

Nu bliver det mere interessant. I dette eksempel definerer vi en metode til beregning af Fibonacci-sekvensen. Når metoden er defineret, kontrollerer vi for at se, hvilke metoder der er defineret med /metoder kommando. Endelig udfører vi et kodestykke for at løkke gennem et array og udskrive de første par tal i sekvensen.

Liste 2. Beregn Fibonacci-sekvensen

 $ bash ./scripts/run.sh | Velkommen til JShell - Version 0.710 | Indtast / hjælp til hjælp -> langt retracement (langt tal) >> hvis ((nummer == 0) | Tilføjet metode retracement (lang) -> / metoder | Fibonacci (lang) lang -> Fibonacci (12) | Udtryksværdi er : 144 | tildelt midlertidig variabel $ 1 af typen lang -> int [] array = {1,2,3,4,5,6,7,8}; | Tilføjet variabel array af typen int [] med startværdi [I @ 4f4a7090 -> for (lang i: array) {System.out.println (Fibonacci (i));} 1 1 2 3 5 8 13 21 

I den samme JShell-session kan jeg omdefinere definitionen af ​​Fibonacci-metoden og udføre den samme kode. På denne måde kan du bruge REPL til hurtigt at udføre, ændre og teste nye algoritmer.

Liste 3. REPL til genbrug

 -> langt retracement (langt tal) {>> return 1; >>} | Modificeret metode retracement (lang) -> for (lang i: array) {System.out.println (Fibonacci (i)); } 1 1 1 1 1 1 1 

Definer en klasse

Det følgende eksempel viser, hvordan man definerer en hel klasse i JShell og derefter henviser til den klasse i et udtryk - alt sammen uden at forlade REPL. Evnen til dynamisk at oprette og teste kode frigør dig til hurtigt at eksperimentere og gentage med ny kode.

Notering 4. Dynamisk klassedefinition

 MacOSX: repl tobrien $ bash ./scripts/run.sh | Velkommen til JShell - Version 0.710 | Skriv / hjælp til hjælp -> klasse Person {>> offentlig String name; >> offentlig alder; >> offentlig beskrivelse af streng; >> >> offentlig person (strengnavn, alder, strengbeskrivelse) {>> dette.navn = navn; >> this.age = alder; >> denne.beskrivelse = beskrivelse; >>} >> >> offentlig String toString () {>> returner dette.navn; >>} >>} | Tilføjet klasse Person -> Person p1 = ny person ("Tom", 4, "Kan lide Spiderman"); | Tilføjet variabel p1 af typen Person med startværdi Tom -> / vars | Person p1 = Tom 

Mens evnen til at definere klasser dynamisk er stærk, er det ikke som udviklere klager over at skrive store definitioner med flere linjer i en interaktiv shell. Det er her, begrebet historie og det at blive ved at indlæse og gemme REPL-tilstanden begynder at blive vigtig. Med /historie kommando kan du liste alle udsagn og udtryk, der er evalueret i en REPL.

Notering 5. Kend din / historie

 -> / historik klasse Person {public String name; offentlig alder offentlig beskrivelse af streng; offentlig person (strengnavn, alder, strengbeskrivelse) {this.name = navn; this.age = alder; denne.beskrivelse = beskrivelse; } offentlig String toString () {returner dette.navn; }} Person p1 = ny person ("Tom", 4, "Kan lide Spiderman"); Person p2 = ny person ("Zach", 10, "God til matematik"); / vars p1 p2 / historie 

Du kan derefter gemme din REPL-historie i en fil og navngive den, så den kan indlæses igen senere. Her er et eksempel:

 -> / gem output.repl -> / reset | Nulstiller tilstand. -> / vars -> / open output.repl -> / vars | Person p1 = Tom | Person p2 = Zach 

Det /Gemme kommandoen gemmer REPL-historikken i en fil, /Nulstil kommandoen nulstiller tilstanden for REPL og /åben kommandoen læser i en fil og udfører tilstande mod REPL. Gemme og åbne funktioner giver dig mulighed for at oprette meget komplekse REPL-scripts, som du kan bruge til at konfigurere forskellige REPL-scenarier.

Redigering af klassedefinition på farten

JShell gør det også muligt at indstille en startdefinitionsfil og indlæse definitioner automatisk. Du kan hoppe rundt i din REPL-historie og redigere navngivne kildeposter. For eksempel, hvis jeg ville ændre definitionen af Person klasse fra dette eksempel kunne jeg bruge /liste og /redigere kommandoer.

Fortegnelse 6. Ændring af person

 -> / l 1: klasse Person {public String name; offentlig int alder offentlig beskrivelse af streng; offentlig person (strengnavn, alder, strengbeskrivelse) {this.name = navn; this.age = alder; denne.beskrivelse = beskrivelse; } offentlig String toString () {returner dette.navn; }} 2: Person p1 = ny person ("Tom", 4, "Kan lide Spiderman"); 3: Person p2 = ny person ("Zach", 10, "God til matematik"); 4: p1 5: p2 -> / rediger 1 

Kører dette /redigere kommandoen indlæser en simpel editor, hvor jeg kan ændre klassedefinitionen og få klassen opdateret med det samme.

Hvad er big deal?

Tal med en Clojure- eller LISP-programmør om, hvordan de udvikler sig dagligt, og du vil se, at de koder inden for en REPL. De skriver ikke scripts og udfører dem så meget, som de bruger det meste af deres udviklingstid på at ændre kode interaktivt. Hvis du har et par timer til overs, så spørg en Scala- eller Clojure-udvikler om deres REPL. Sådan fungerer de.

Java er et andet sprog end Scala eller Clojure. Java-udviklere bruger ikke dage med fokus på enkeltlinjer af LISP, der kan indeholde hele programstrukturer i nogle få udsagn. De fleste Java-programmer kræver opsætning for at fungere korrekt, og mens nylige ændringer af sproget har reduceret antallet af linier for systemer skrevet i Java, måler vi stadig kompleksiteten af ​​vores systemer i tusinder af kodelinjer. Det enkle Person eksemplet, der er anført ovenfor, er ikke nyttig kode, og den mest nyttige kode i Java bærer en kompleksitet, der bliver vanskelig at passe ind i et REPL-baseret programmeringsmiljø.

Scala og Clojure-udviklere praktiserer noget, der Programmering af Clojure forfatter Chas Emerick kalder "iterativ udvikling", der ikke afhænger af en filbaseret arbejdsgang. Java-udviklere er afhængige af snesevis af biblioteker, komplekse afhængighedshierarkier og containere som Tomcat eller TomEE. Af denne grund forudsiger jeg ikke, at REPL-orienteret programmering overgår traditionel Java-udvikling i en IDE. I stedet ser jeg Java REPL give et par forskellige fordele og muligheder.

1. At lære Java: Fordi Java-programmer kræver så meget opsætning, kan det være en udfordring for udviklere, der lærer sproget, at forstå syntaksen hurtigt. Java 9's REPL bliver den primære måde, hvorpå nye udviklere kommer til at forstå den basale syntaks.

2. Eksperimentere med nye biblioteker: Java har hundredvis af nyttige open source-biblioteker til alt fra dato- og tidsmanipulation til matematiske biblioteker. Uden en REPL, når en udvikler ønsker at forstå et nyt bibliotek, opretter de uundgåeligt et par smidige klasser med det sædvanlige "offentlig statisk ugyldig hoved"ceremoni. Med en REPL kan du bare skyde den op og spille uden denne overhead.

3. Hurtig prototyping: Dette er tættere på, hvordan de fleste Clojure- og Scala-udviklere arbejder iterativt, men hvis du arbejder på et fokuseret problem, gør en REPL det let at gentage hurtigt om ændringer i klasser og algoritmer. Med en REPL behøver du ikke vente på, at en build er færdig; du kan tilpasse definitionen af ​​en klasse hurtigt, nulstille din REPL og prøve den igen.

4. Integration med byggesystemer: Gradle tilbyder en interaktiv "shell" -tilstand, og Maven-samfundet har tidligere leveret lignende værktøjer. Udviklere, der ønsker at reducere kompleksiteten i byggeriet, kunne udforske at bruge en REPL som et værktøj til at orkestrere andre systemer.

Min sidste 2c

Jeg ser Java REPL som noget, der begynder at påvirke den daglige udvikling i de næste par år, for dem der opgraderer til Java 9. Jeg tror også, at Java-samfundet har brug for tid til fuldt ud at tilpasse sig ny udviklingsstil og forstå både de udfordringer og muligheder, som en REPL giver. Jeg forventer ikke, at de fleste Java-udviklere overgår til REPL-orienteret udvikling, som deres fætre i Clojure-programmering har, men jeg tror, ​​at vi vil se REPL påvirke den måde, som nye udviklere lærer Java på. Da nye Java-udviklere støder på Java for første gang i en REPL, er der ingen tvivl om, at det vil begynde at påvirke, hvordan vi bygger og prototype Java-baserede systemer.

Denne historie, "Hvad REPL betyder for Java" blev oprindeligt udgivet af JavaWorld.