JShell to Java shell - program dostępny w Java 9, który pozwala na pisanie i uruchamianie kodu w Java wg. schematu REPL
Program JShell działa w trybie tekstowym. Umożliwia szybkie testowanie pomysłów i sprawdzanie wyniku pracy naszego kodu bez konieczności jego ręcznej kompilacji i uruchamiania - procesem tym zajmuje się JShell.
JShell uruchamiany jest za pomocą polecenia:
$ katalogZjdk9/bin/jshell | Welcome to JShell -- Version 9 | For an introduction type: /help intro jshell> _
Pierwszy "program" (a właściwie fragment kodu/wstawka ang. snippet) jest bardzo prosty, pokazuje jednak siłę nowego narzędzia. Kodu, który ma wykonać pracę, nie trzeba opakowywać w klasy czy metody. Wystarczy wpisać:
jshell> System.out.println( "Czesc!" )[Enter] Czesc! jshell> _
Od razu mamy efekt...
A teraz pierwszy program napisany z pomocą klawisza [Tab]. Ale najpierw mały pokaz możliwości.
jshell> Sy[Tab] SyncFailedException SynchronousQueue System jshell> Sys[Tab] System jshell> System[Tab] System Signatures: java.lang.System <press tab again to see documentation> jshell> System[Tab] java.lang.System The System class contains several useful class fields and methods.It cannot be instantiated. Among the facilities provided by the System class are standard input, standard output, and error output streams; access to externally defined properties and environment variables; a means of loading files and libraries; and a utility method for quickly copying a portion of an array. jshell> _
A teraz obiecany program:
jshell> System.[Tab] Logger LoggerFinder arraycopy( class clearProperty( console() currentTimeMillis() err exit( gc() getLogger( getProperties() getProperty( getSecurityManager() getenv( identityHashCode( in inheritedChannel() lineSeparator() load( loadLibrary( mapLibraryName( nanoTime() out runFinalization() runFinalizersOnExit( setErr( setIn( setOut( setProperties( setProperty( setSecurityManager( jshell> System.o[Tab] out jshell> System.out.[Tab] append( checkError() close() equals( flush() format( getClass() hashCode() notify() notifyAll() print( printf( println( toString() wait( write( jshell> System.out.print[Tab] print( printf( println( jshell> System.out.printl[Tab] println( jshell> System.out.println("Czesc") Czesc
A teraz coś o /help.
Aby uzyskać pomoc w kwestii wbudowanych w jshell poleceń wpisujemy po prostu:
/help
Pojawia się lista dostępnych poleceń z krótkim ich omówieniem. Na początek warto poznać:
Przykład użycia:
jshell> /? /list | | /list | | Show the source of snippets, prefaced with the snippet id. | | /list | List the currently active snippets of code that you typed or read with /open | | /list -start | List the automatically evaluated start-up snippets | | /list -all | List all snippets including failed, overwritten, dropped, and start-up | | /list| List snippets with the specified name (preference for active snippets) | | /list | List the snippet with the specified snippet id
jshell> 2+2 $1 ==> 4 jshell> $1 $1 ==> 4 jshell> $1+2 $3 ==> 6 jshell> /list 1 : 2+2 2 : $1 3 : $1+2 jshell> /list $1 1 : 2+2
Jak widać wyniki naszej pracy są dostępne poprzez automatycznie tworzone zmienne (tutaj $1 i $3).
Policzmy teraz obwód koła o promieniu $1. Aby tego dokonać potrzebna jest wartość Π. Oczywiście można ją wpisać ręcznie. Lepiej jednak użyć stałej dostępnej w Java:
jshell> Math.PI[Tab] PI Signatures: Math.PI:double <press tab again to see documentation> jshell> Math.PI[Tab] Math.PI:double The double value that is closer than any other to pi , the ratio of the circumference of a circle to its diameter. jshell> 2*Math.PI*$1 $4 ==> 25.132741228718345
Może pojawić się pytanie: jakie zmienne pojawiły się w trakcie pracy z JShell i jakiego są one typu? Nic prostrzego. Można się o tym dowiedzieć za pomocą wbudowanego polecenia /vars.
jshell> /vars | int $1 = 4 | int $3 = 6 | double $4 = 25.132741228718345 jshell> /vars $4 | double $4 = 25.132741228718345
Aby utworzyć własną zmienną musimy podać jej nazwę poprzedzoną nazwą typu. Zmiennych można potem używać w obliczeniach.
jshell> int a = 10 a ==> 10 jshell> a + 1 $2 ==> 11 jshell> /! a + 1 $3 ==> 11
Przy okazji: wbudowane w JShell polecenie /! pozwala na powtórne wykonanie ostatniego fragmentu kodu.
Fragmenty kodu, które wpisujemy do JShell otrzymują kolejne identyfikatory liczbowe. Można je poznać wpisując polecnie /list:
jshell> int a = 10 a ==> 10 jshell> a + 1 $2 ==> 11 jshell> a + 2 $3 ==> 12 jshell> /list 1 : int a = 10; 2 : a + 1 3 : a + 2
Jeśli chcemy uruchmić wybrany fragment kodu używamy wbudowanego w JShell polecenia /<id>, gdzie <id>, to numer fragmentu kodu, który nas interesuje. Np.:
jshell> /3 a + 2 $4 ==> 12
Istnieje możliwość zadeklarowania zmiennej referencyjnej, o typie, który nie jest jeszcze znany (utworzony). Zmienna istnieje, ale nie można jej używać...
jshell> Kot k | created variable k, however, it cannot be referenced until class Kot is declared
W Java metody tworzone są wewnątrz klas czy interfejsów (od Java 8). W JShell możemy utworzyć metodę niejako wprost.
jshell> void poleKwadratu( int bok ) { ...> System.out.println( "Pole kwadratu o boku " + bok + " to " + 4 * bok ); ...> } | created method poleKwadratu(int) jshell> poleKwadratu(5) Pole kwadratu o boku 5 to 20
Działa... tylko, że w metodzie jest błąd - zamiast pola liczony jest obwód. Jak to poprawić?
jshell> /edit poleKwadratu | modified method poleKwadratu(int)
Wbudowane polecenie /edit otwiera prosty edytor Ascii - w nim znajdujemy kod naszej metody. Wprowadzamy poprawki i klikamy exit.
jshell> poleKwadratu(5) Pole kwadratu o boku 5 to 25
Od razu lepiej. Jeśli wbudowany edytor nam nie odpowiada, to możemy wskazać inny.
/set editor gedit
Od tej chwili polecenie /edit uruchomi edytor o nazwie gedit.
Zapis naszej pracy można zlecić za pomocą polecenia /save, po którym podaje się nazwę pliku, w którym zostanie ona zapisana. Odczyt możliwy jest za pomocą polecenia /open.
A teraz przykład prostej klasy. Zaczynamy od utworzenia referencji do obiektu klasy
Kot
, a potem tworzymy klasę z jedną metodą mrr
.
jshell> Kot kot; | created variable kot, however, it cannot be referenced until class Kot is declared jshell> class Kot { ...> void mrr() { ...> System.out.println("Mrrrrr...."); ...> } ...> } | created class Kot | update replaced variable kot, reset to null jshell> kot = new Kot() kot ==> Kot@42dafa95 jshell> kot.mrr() Mrrrrr....
Jak widać, po utworzeniu klasy Kot
JShell przypomniał sobie o zminnej
kot
i zainicjował ją wartością null
.
Sprawdzmy co się stanie gdy wykonamy niestatyczną metodę posługując się
referencją, w której jest null
.
jshell> kot = null kot ==> null jshell> kot.mrr() | java.lang.NullPointerException thrown: | at (#6:1) jshell> /list 1 : Kot kot; 2 : class Kot { void mrr() { System.out.println("Mrrrrr...."); } } 3 : kot = new Kot() 4 : kot.mrr() 5 : kot = null 6 : kot.mrr()
JShell zgłasza problem i działa nadal. Wskazuje na numer fragmentu kodu, w którym pojawił się wyjątek.