מה המשמעות של REPL עבור Java

אולי אתה מפתח Clojure או Scala בארון, או אולי עבדת עם LISP בעבר. אם כן, יש סיכוי טוב שהשתמשת ב- REPL כחלק משגרת יומך. REPL , או read-eval-print-loop, הוא ממשק מעטפת שקורא כל שורת קלט, מעריך את השורה ואז מדפיס את התוצאה. משוב מיידי, נחמד!

כאשר אתה משתמש ב- REPL, אתה כותב קוד באופן אינטראקטיבי ומבצע אותו ללא דיחוי. שחרורו של Java 9 בשנת 2016 יספק סביבת REPL מתפקדת לחלוטין בשם JShell (בשם קוד Kulla). מאמר זה מספק סקירה כללית של Java REPL ודן בכמה אפשרויות כיצד תוכלו להשתמש בו בתכנות ה- Java שלכם - כן, אתם!

רגע, לג'אווה אין כבר REPL?

אין ספק ששפה מבוססת כמו Java חייבת להיות בעלת REPL! ובכן, למעשה, לא בכל השפות יש אותן וג'אווה היא אחת מאלה שחסרה לה. ניתן לטעון, עם יותר טקסים ופלטים מרוב השפות, ג'אווה היא אחת השפות שהמפתחים היו ראויים לה ביותר. לג'אווה היה משהו קצת כמו REPL במשך זמן מה בדמות Java BeanShell, אך פרויקט זה מעולם לא היה REPL בעל אופי מלא המשתווה לאלה של שפות אחרות. זו הייתה רק תת קבוצה של התחביר המלא של שפת Java.

REPL מפחית תפנית

קיצור זמן ההסבה ולולאות המשוב ככל האפשר חשוב להפליא לשפיות מפתח. REPL הוא כלי נהדר עבור מפתחים שרוצים להשיג בדיוק את זה. מפתחים הם יצרניים ביותר כאשר הם יכולים לראות את תוצאות עבודתם באופן מיידי. בעזרת Java REPL, מפתחים יוכלו לכתוב קוד, לבצע קוד זה, ואז להמשיך ולפתח את הקוד שלהם תוך כדי תנועה מבלי שיצטרכו לצאת על מנת להריץ build וכו '. בעוד שרבות מהמערכות המשתמשות בג'אווה הן מעבר למורכבות של מה שניתן לטפל בו באמצעות REPL אינטראקטיבי, עצם הימצאותו של REPL ב- JDK פירושו שמישהו, איפשהו ימצא מקרה שימוש מדהים עבורו תוך זמן קצר. העובדה ש- JShell חושף ממשק API מבטיחה בעצם שמפתחי IDE הולכים לשלב את ה- REPL הזה בכלים בהם אנו משתמשים לכתיבת קוד.רק המתן עד שג'אווה REPL יהיה חלק מכל IDE!

התחל לעבוד עם JShell

חשוב להבין כי השימוש ב- REPL בפיתוח, פרויקט קולה, אינו מיועד לבעלי לב חלש. Kulla, המכונה JShell, אינו חלק מחבילת התצוגה המקדימה של JDK 9 בעת כתיבת שורות אלה, כך שתצטרך לשכפל פרויקט של Mercurial, להרכיב את ה- JDK ולהרכיב את JShell בעצמך. הקדיש שעה לתהליך זה, במיוחד אם אתה בדרך כלל לא זורק קוד JDK. יהיה עליך להשבית אזהרות כשגיאות, ואם אתה בונה על OSX וודא שהתקנת את XCode יחד עם XQuartz עבור ספריית סוג חופשי. עקוב אחר ההוראות שלהלן כדי להתקין ולהפעיל את Project Kulla בסביבת הפיתוח שלך ב- Java.

1. התקן את Java 9

כדי להפעיל את JShell יהיה עליך להוריד ולהתקין את התצוגה המקדימה האחרונה של הגישה המוקדמת לגישה מוקדמת עבור Java 9. לאחר שהורדת את Java 9 הגדר את JAVA_HOMEמשתנה הסביבה שלך והפעל java –versionכדי לאמת את ההתקנה שלך. זה יכול להיות כאב, במיוחד ב- OSX, אז כדאי לבדוק זאת פעמיים!

2. התקן את Mercurial ואת Project Kulla

Project Kulla הוא פרויקט OpenJDK, כך שתצטרך לשכפל את מאגר Mercurial כדי להרכיב אותו.

לאחר מכן תשכפל את מאגר Kulla:

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

ואז תגדיר את ה- build:

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

3. הידור והפעל את REPL

הנה הקוד להרכבת REPL:

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

והנה הקוד להפעלתו:

 bash ./scripts/run.sh 

כפי שציינתי, תכונת ה- REPL של ג'אווה עדיין לא מוכנה לצריכה כללית, אך עדיין נוכל לקחת אותה לנסיעת מבחן מוקדמת!

אתה עושה את המתמטיקה

לדוגמא ראשונית למה ש- JShell יכול לעשות, בואו נעריך כמה ביטויים פשוטים באמצעות java.lang.Math:

רישום 1. הערכת ביטויים מתמטיים באמצעות 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 

כאן אנו מעריכים ביטויים, מוצאים את השורש הריבועי של מספר ואז מוסיפים שני מספרים יחד. זה לא הקוד המורכב ביותר, אך עליך לשים לב כי /varsהפקודה נותנת לנו את היכולת לרשום את המשתנים שנוצרו בהפעלה JShell. אנו יכולים להתייחס לערכים של ביטויים שלא הוקצו באמצעות סימן דולר ($). לבסוף אנו יכולים ליצור משתנה חדש ולהקצות לו ערך.

הגדירו שיטה

עכשיו זה נהיה מעניין יותר. בדוגמה זו אנו מגדירים שיטה לחישוב רצף פיבונאצ'י. לאחר הגדרת השיטה, אנו בודקים אילו שיטות מוגדרות באמצעות /methodsהפקודה. לבסוף, אנו מבצעים קטע קוד שיעבור במערך ונדפיס את המספרים הראשונים ברצף.

רישום 2. חשב את רצף פיבונאצ'י

 $ 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 

באותה הפעלת JShell אני יכול להגדיר מחדש את ההגדרה של שיטת פיבונאצ'י ולבצע את אותו קוד. באופן זה תוכלו להשתמש ב- REPL לביצוע מהיר, שינוי ובדיקה של אלגוריתמים חדשים.

רישום 3. REPL לשימוש חוזר

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

הגדר כיתה

הדוגמה הבאה מדגימה כיצד להגדיר מחלקה שלמה ב- JShell ואז להתייחס למחלקה זו בביטוי - הכל מבלי לעזוב את REPL. היכולת ליצור ולבדוק דינמי קוד משחררת אותך להתנסות במהירות ולחזור באמצעות קוד חדש.

רישום 4. הגדרת כיתה דינמית

 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 

היכולת להגדיר שיעורים באופן דינמי היא אמנם חזקה, אך לא כמו שמפתחים מתלהבים לכתוב הגדרות גדולות ורב-שורות במעטפת אינטראקטיבית. זה המקום שבו מושג ההיסטוריה והעומד לטעון ולשמור את מצב ה- REPL מתחילים להיות חשובים. באמצעות /historyהפקודה תוכלו לרשום את כל ההצהרות והביטויים שהוערכו ב- REPL.

רישום 5. דע את / ההיסטוריה שלך

 -> /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

אני רואה את Java REPL כמשהו שיתחיל להשפיע על ההתפתחות היום יומית במהלך השנים הקרובות, עבור אלה שמשדרגים ל- Java 9. אני גם חושב שקהילת Java תצטרך זמן להסתגל באופן מלא ל סגנון פיתוח חדש ומבין את האתגרים וההזדמנויות שמציע REPL. אני לא מצפה שרוב מפתחי Java יעברו להתפתחות מוכוונת REPL כמו שיש לבני דודיהם לתכנות Clojure, אבל אני כן נראה שנראה כי REPL משפיע על הדרך שבה מפתחים חדשים לומדים את Java. כאשר מפתחי ג'אווה חדשים נתקלים בג'אווה בפעם הראשונה בתוך REPL, אין ספק שהיא תתחיל להשפיע על האופן שבו אנו בונים ומערכות-טיפוס מבוססות Java.

סיפור זה, "מה המשמעות של REPL עבור Java" פורסם במקור על ידי JavaWorld.