Arti REPL untuk Java

Mungkin Anda adalah pengembang Clojure lemari atau Scala, atau mungkin Anda pernah bekerja dengan LISP di masa lalu. Jika demikian, ada kemungkinan Anda telah menggunakan REPL sebagai bagian dari rutinitas harian Anda. REPL , atau read-eval-print-loop, adalah antarmuka shell yang membaca setiap baris input, mengevaluasi baris tersebut, dan kemudian mencetak hasilnya. Umpan balik instan, bagus!

Saat Anda menggunakan REPL, Anda menulis kode secara interaktif dan menjalankannya tanpa penundaan. Rilis Java 9 pada tahun 2016 akan menghadirkan lingkungan REPL yang berfungsi penuh bernama JShell (nama kode Kulla). Artikel ini memberikan gambaran umum tentang REPL Java dan membahas beberapa kemungkinan bagaimana Anda dapat menggunakannya dalam pemrograman Java Anda - ya, Anda!

Tunggu, Java belum memiliki REPL?

Tentunya bahasa mapan seperti Java harus memiliki REPL! Sebenarnya, tidak semua bahasa memilikinya dan Java adalah salah satu yang tidak memilikinya. Bisa dibilang, dengan lebih banyak upacara dan boilerplate daripada kebanyakan bahasa, Java adalah salah satu bahasa yang paling pantas didapatkan oleh pengembang. Java telah memiliki sesuatu yang agak mirip REPL untuk sementara waktu dalam bentuk Java BeanShell, tetapi proyek ini tidak pernah menjadi REPL berfitur lengkap yang setara dengan bahasa lain. Itu hanya bagian dari sintaks bahasa Java lengkap.

REPL mengurangi perputaran

Mempersingkat waktu penyelesaian dan putaran umpan balik sebanyak mungkin sangat penting bagi kewarasan pengembang. REPL adalah alat yang hebat untuk pengembang yang ingin mencapai hal itu. Pengembang paling produktif ketika mereka dapat melihat hasil pekerjaan mereka dengan segera. Dengan Java REPL, pengembang akan dapat menulis kode, mengeksekusi kode itu, dan kemudian terus mengembangkan kode mereka saat itu juga tanpa harus keluar untuk menjalankan build dan seterusnya. Sementara banyak sistem yang menggunakan Java berada di luar kompleksitas dari apa yang dapat ditangani oleh REPL interaktif, kehadiran REPL di JDK berarti bahwa seseorang, di suatu tempat akan menemukan kasus penggunaan yang luar biasa untuk itu dalam waktu singkat. Fakta bahwa JShell mengekspos API pada dasarnya memastikan bahwa pengembang IDE akan mengintegrasikan REPL ini ke dalam alat yang kami gunakan untuk menulis kode.Tunggu saja sampai REPL Java menjadi bagian dari setiap IDE!

Mulailah dengan JShell

Penting untuk disadari bahwa menggunakan REPL dalam pengembangan, Project Kulla, bukanlah untuk menjadi lemah hati. Kulla, alias JShell, bukan bagian dari bundel pratinjau JDK 9 pada saat penulisan, jadi Anda harus mengkloning proyek Mercurial, mengkompilasi JDK, dan mengkompilasi JShell sendiri. Luangkan waktu satu jam untuk proses ini, terutama jika Anda biasanya tidak menggunakan kode sumber JDK. Anda harus menonaktifkan peringatan sebagai kesalahan, dan jika Anda membangun di OSX pastikan Anda telah menginstal XCode bersama dengan XQuartz untuk pustaka freetype. Ikuti petunjuk di bawah ini untuk menginstal dan menjalankan Project Kulla di lingkungan pengembangan Java Anda.

1. Instal Java 9

Untuk menjalankan JShell Anda harus mengunduh dan menginstal versi pratinjau akses awal terbaru untuk Java 9. Setelah Anda mengunduh Java 9, setel JAVA_HOMEvariabel lingkungan Anda dan jalankan java –versionuntuk memverifikasi pemasangan Anda. Ini bisa menyebalkan, terutama di OSX, jadi perlu diperiksa ulang!

2. Pasang Mercurial dan Project Kulla

Project Kulla adalah proyek OpenJDK jadi Anda harus mengkloning repositori Mercurial untuk mengkompilasinya.

Selanjutnya Anda akan mengkloning repositori Kulla:

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

Kemudian Anda akan mengonfigurasi build:

 cd kulla bash ./configure --disable-warnings-as-errors make images 

3. Kompilasi dan jalankan REPL

Berikut kode untuk mengkompilasi REPL:

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

Dan inilah kode untuk menjalankannya:

 bash ./scripts/run.sh 

Seperti yang saya catat, fitur REPL Java belum siap untuk konsumsi umum, tetapi kami masih dapat menggunakannya untuk test drive awal!

Anda melakukan matematika

Untuk contoh awal tentang apa yang dapat dilakukan JShell, mari kita evaluasi beberapa ekspresi sederhana menggunakan java.lang.Math:

Kode 1. Mengevaluasi ekspresi matematika dengan REPL

 $ bash ./scripts/run.sh | Welcome to JShell -- Version 0.710 | Type /help for help -> Math.sqrt( 144.0f ); | Expression value is: 12.0 | assigned to temporary variable $1 of type double -> $1 + 100; | Expression value is: 112.0 | assigned to temporary variable $2 of type double -> /vars | double $1 = 12.0 | double $2 = 112.0 -> double val = Math.sqrt( 9000 ); | Added variable val of type double with initial value 94.86832980505137 

Di sini kita mengevaluasi ekspresi, mencari akar kuadrat dari sebuah angka, dan kemudian menjumlahkan dua angka. Ini bukan kode yang paling rumit, tetapi Anda harus perhatikan bahwa /varsperintah tersebut memberi kita kemampuan untuk membuat daftar variabel yang dibuat dalam sesi JShell. Kita bisa merujuk ke nilai ekspresi yang belum ditetapkan menggunakan notasi tanda dolar ($). Terakhir kita bisa membuat variabel baru dan memberinya nilai.

Tentukan metode

Sekarang menjadi lebih menarik. Dalam contoh ini kami mendefinisikan metode untuk menghitung deret Fibonacci. Setelah metode ditentukan, kami memeriksa untuk melihat metode mana yang didefinisikan dengan /methodsperintah. Akhirnya, kami mengeksekusi potongan kode untuk mengulang melalui array dan mencetak beberapa angka pertama dalam urutan.

Kode 2. Hitung deret Fibonacci

 $ bash ./scripts/run.sh | Welcome to JShell -- Version 0.710 | Type /help for help -> long fibonacci(long number)  >> if ((number == 0)  | Added method fibonacci(long) -> /methods | fibonacci (long)long -> fibonacci( 12 ) | Expression value is: 144 | assigned to temporary variable $1 of type long -> int[] array = { 1,2,3,4,5,6,7,8 }; | Added variable array of type int[] with initial value [[email protected] -> for( long i : array ) { System.out.println(fibonacci( i )); } 1 1 2 3 5 8 13 21 

Dalam sesi JShell yang sama, saya dapat mendefinisikan kembali definisi metode Fibonacci dan mengeksekusi kode yang sama. Dengan cara ini Anda dapat menggunakan REPL untuk menjalankan, memodifikasi, dan menguji algoritma baru dengan cepat.

Kode 3. REPL untuk digunakan kembali

 -> long fibonacci(long number) { >> return 1; >> } | Modified method fibonacci(long) -> for( long i : array ) { System.out.println(fibonacci( i )); } 1 1 1 1 1 1 1 

Tentukan kelas

The following example demonstrates how to define an entire class in JShell and then reference that class in an expression -- all without leaving the REPL. The ability to dynamically create and test code frees you up to quickly experiment and iterate with new code.

Listing 4. Dynamic class definition

 MacOSX:repl tobrien$ bash ./scripts/run.sh | Welcome to JShell -- Version 0.710 | Type /help for help -> class Person { >> public String name; >> public int age; >> public String description; >> >> public Person( String name, int age, String description ) { >> this.name = name; >> this.age = age; >> this.description = description; >> } >> >> public String toString() { >> return this.name; >> } >> } | Added class Person -> Person p1 = new Person( "Tom", 4, "Likes Spiderman" ); | Added variable p1 of type Person with initial value Tom -> /vars | Person p1 = Tom 

While the ability to define classes dynamically is powerful it isn't like developers are clamoring to write large, multi-line definitions in an interactive shell. This is where the concept of history and being about to load and save the state of the REPL starts to become important. With the /history command you can list all of the statements and expressions evaluated in a REPL.

Listing 5. Know your /history

 -> /history class Person { public String name; public int age; public String description; public Person( String name, int age, String description ) { this.name = name; this.age = age; this.description = description; } public String toString() { return this.name; } } Person p1 = new Person( "Tom", 4, "Likes Spiderman" ); Person p2 = new Person( "Zach", 10, "Good at Math" ); /vars p1 p2 /history 

You can then save your REPL history to a file and name it so that it can be loaded again later. Here's an example:

 -> /save output.repl -> /reset | Resetting state. -> /vars -> /open output.repl -> /vars | Person p1 = Tom | Person p2 = Zach 

The /save command saves the REPL history to a file, the /reset command resets the state of the REPL, and the /open command reads in a file and executes states against the REPL. The save and open features enable you to set up very complex REPL scripts that you can use to configure different REPL scenarios.

Editing class definition on the fly

JShell also makes it possible to set a startup definition file and load definitions automatically. You can jump around your REPL history and edit named source entries. For example, if I wanted to modify the definition of the Person class from this example I could use the /list and /edit commands.

Listing 6. Modifying Person

 -> /l 1 : class Person { public String name; public int age; public String description; public Person( String name, int age, String description ) { this.name = name; this.age = age; this.description = description; } public String toString() { return this.name; } } 2 : Person p1 = new Person( "Tom", 4, "Likes Spiderman" ); 3 : Person p2 = new Person( "Zach", 10, "Good at Math" ); 4 : p1 5 : p2 -> /edit 1 

Running this /edit command loads a simple editor where I can alter the class definition and have the class updated immediately.

What's the big deal?

Talk to a Clojure or LISP programmer about how they develop day to day, and you'll see that they code within a REPL. They don't write scripts and then execute them as much as they spend most of their development time changing code interactively. If you have a few hours to spare, ask a Scala or Clojure developer about their REPL. It's how they work.

Java's a different language from Scala or Clojure. Java developers are not spending days focused on single lines of LISP that might contain entire program structures in a few statements. Most Java programs require setup to function properly, and while recent changes to the language have reduced the line count of systems written in Java we're still measuring the complexity of our systems in thousands of lines of code. The simple Person example listed above isn't useful code, and most useful code in Java carries with it a complexity that's going to be difficult to fit into a REPL-based programming environment.

Scala and Clojure developers practice something that Clojure Programming author Chas Emerick calls "iterative development" that doesn't depend on a file-based workflow. Java developers depend on tens of libraries, complex dependency hierarchies, and containers like Tomcat or TomEE. For this reason I don't predict that REPL-oriented programming will overtake traditional Java development in an IDE. Instead I see the Java REPL providing a few distinct benefits and opportunities.

1. Learning Java: Because Java programs require so much setup it can be challenging for developers learning the language to understand the syntax quickly. Java 9's REPL will become the primary way that new developers come to grips with the basic syntax.

2. Experimenting with new libraries: Java has hundreds of useful open source libraries for everything from date and time manipulation to math libraries. Without a REPL, whenever a developer wants to understand a new library they inevitably create a few throwaway classes with the usual "public static void main" ceremony. With a REPL you can just fire it up and play without this overhead.

3. Rapid prototyping: This is closer to how most Clojure and Scala developers work iteratively, but if you are working on a focused problem, a REPL makes it easy to iterate quickly on changes to classes and algorithms. With a REPL you won't have to wait for a build to finish; you can tweak the definition of a class quickly, reset your REPL, and try it again.

4. Integration with build systems: Gradle provides an interactive "shell" mode, and the Maven community have shipped similar tools in the past. Developers looking to reduce build complexity could explore using a REPL as a tool to orchestrate other systems.

My final 2c

Saya melihat Java REPL sebagai sesuatu yang akan mulai mempengaruhi pengembangan sehari-hari selama beberapa tahun ke depan, bagi mereka yang meningkatkan ke Java 9. Saya juga berpikir bahwa komunitas Java akan membutuhkan waktu untuk sepenuhnya menyesuaikan diri dengan gaya pengembangan baru dan memahami baik tantangan dan peluang yang disediakan REPL. Saya tidak berharap bahwa sebagian besar pengembang Java akan beralih ke pengembangan berorientasi REPL seperti yang dimiliki oleh sepupu pemrograman Clojure mereka, tetapi saya pikir kita akan melihat REPL memengaruhi cara pengembang baru mempelajari Java. Ketika pengembang Java baru menemukan Java untuk pertama kalinya dalam REPL, tidak ada keraguan bahwa itu akan mulai memengaruhi cara kami membangun dan membuat prototipe sistem berbasis Java.

Artikel ini, "Arti REPL untuk Java", awalnya diterbitkan oleh JavaWorld.