Java
jshell
Java11
JDK11

Learn JDK11 with JShell (2018/12/15 JJUG CCC 2018 Fall)


About me


  • Naoki Kishida

  • LINE Fukuoka

  • Twitter: @kis



Agenda


  • What is JShell (30 min)

  • What's new in JDK11 (50 min)

  • What's new in JDK12 (20 min)

total: 100 min



What is JShell



JShell


  • REPL (Read-Eval-Print-Loop)

  • Command line tool to evaluate a Java code snipets interactively

  • Entering a programming element, we can get the result immediately



JShell install and start

スクリーンショット 2018-10-21 9.27.21.png



Haven't installed JDK11+ yet?

Web JShell console

https://tryjshell.org/

スクリーンショット 2018-10-21 8.44.59.png



Restriction of TryJShell

JFrame is not allowed since TryJShell is a headless

スクリーンショット 2018-10-21 8.45.33.png



/exit


  • Exit JShell


  • /exi /ex also are allowed

We can abbreviate a command while it is not ambiguous

jshell> /exit

| Goodbye
~ $



/help


  • Show information

  • To specify a command to show the detail

jshell> /he help

|
| /help
| =====
|
| Display information about using the jshell tool.
...



Expression

JShell returns a result of an expression you have entered.

jshell> 23 * 12

$1 ==> 276

jshell> Math.sqrt(2)
$2 ==> 1.4142135623730951



Variable

You can define variables

jshell> String s = "Hello"

s ==> "Hello"

jshell> s
s ==> "Hello"



var in JShell

var fits in well with JShell

jshell> var strs = List.of("aa", "bb")

strs ==> [aa, bb]



Scratch variable


  • Expression without a named variable will create a scratch variable

  • Scratch variable is $ + number form

  • We can refer the value with the scratch variable

jshell> "hello"

$6 ==> "hello"

jshell> $6.toUpperCase()
$7 ==> "HELLO"



/vars

Show declared variables

jshell> 23+4

$1 ==> 27

jshell> var a = "hello"
a ==> "hello"

jshell> /vars
| int $1 = 27
| String a = "hello"



/vars


  • can specify a variable name

  • can specify a variable id

jshell> /vars a

| String a = "hello"

jshell> /vars $1
| int $1 = 27

jshell> /vars 1
| int $1 = 27



Change definitions

We can change definitions of a variable (or method, class) defined in JShell by entering new definition.

jshell> var s = "hello"

s ==> "hello"

jshell> /vars s
| String s = "hello"

jshell> var s = 123
s ==> 123

jshell> /vars s
| int s = 123



Completion

[tab] to complete a method, class or variable

jshell> "abc".toU[tab]

jshell> "abc".toUpperCase(



Import completion

We can insert an import by [shift+tab], [i]

jshell> var f = new JFrame[shift+tab],[i]

jshell> var f = new JFrame

0: Do nothing
1: import: javax.swing.JFrame

↓[1]

Choice: 

Imported: javax.swing.JFrame

jshell> var f = new JFrame



Show a method signature and JavaDoc

[tab] to show the method signature after ( at beginning of the method parameter

One more [tab] shows its JavaDoc

jshell> "abc".toUpperCase([tab]

Signatures:
String String.toUpperCase(Locale locale)
String String.toUpperCase()

<press tab again to see documentation>



/imports

Show all imports

jshell> /i

| import java.io.*
| import java.math.*
| import java.net.*
| import java.nio.file.*
| import java.util.*
| import java.util.concurrent.*
| import java.util.function.*
| import java.util.prefs.*
| import java.util.regex.*
| import java.util.stream.*
| import javax.swing.JFrame



Default import

The imports below are imported by default

import java.io.*

import java.math.*
import java.net.*
import java.nio.file.*
import java.util.*
import java.util.concurrent.*
import java.util.function.*
import java.util.prefs.*
import java.util.regex.*
import java.util.stream.*



JDK11



JDK11


  • New in JShell

  • JEPs

  • APIs



What's new on JShell

Allow to open URL


  • on startup

~ $ jshell https://kishida.github.io/misc/jframe.jshell

| Welcome to JShell -- Version 12-ea
| For an introduction type: /help intro


  • on jshell command

jshell> /open https://kishida.github.io/misc/jframe.jshell


kishida.github.io/misc/jframe.jshell

import javax.swing.*

var f = new JFrame("JShell")
f.setSize(400, 300)
f.setVisible(true)



JEPs

There are 16 JEPs in JDK11

スクリーンショット 2018-10-20 9.39.39.png



Today's JEPs


  • 321: HTTP Client(Standard)

  • 181: Nest-Based Access Control

  • 323: Local-Variable Syntax for Lambda Parameters



321: HTTP Client(Standard)


  • Modern API

  • HTTP2 support

  • WebSocket

  • Reactive

The new HTTP Client API in Java 11 [DEV5951]

Oct 23, 04:00 PM - 04:45 PM | Room 2004



HTTP Client Component


  • HttpClient

  • HttpRequest

  • HttpResponse

  • BodyHandler

  • BodySubscriber

  • WebSocket

  • and more...



HTTP Client Basis

HTTP Client basic usage

var client = HttpClient.newHttpClient();

var request = HttpRequest.newBuilder()
.uri(URI.create("http://openjdk.java.net/"))
.build();
HttpResponse<String> res = client.send(
request,
HttpResponse.BodyHandlers.ofString());
System.out.println(res.statusCode());
System.out.println(res.body());



HTTP Client step by step


  • import java.net.http.*

  • Prepare HttpClient

  • Prepare HttpRequest with builder

  • Send the request using the client


  • HttpResponse will be returned

  • Process the response



import java.net.http.*

HTTP Client API is under java.net.http package


  • java.net.http.HttpClient

  • java.net.http.HttpRequest

  • java.net.http/HttpResponse

jshell> import java.net.http.*



Prepare HttpClient

Using a factory method newHTtpClient()

jshell> var client = HttpClient.newHttpClient()

client ==> jdk.internal.net.http.HttpClientImpl@5ad851c9(1)



Configure HttpClient

Use a builder to configure HttpClient

jshell> import java.net.http.HttpClient.*

jshell> var client2 = HttpClient.newBuilder().
...> version(Version.HTTP_2).
...> followRedirects(Redirect.NORMAL).
...> build()
client2 ==> jdk.internal.net.http.HttpClientImpl@574b560f(1)

Terminate a line with . to span a snippet into multiple lines

or the expression will be evaluated as the Builder



Prepare HttpRequest with builder

jshell> var request = HttpRequest.newBuilder(

...> URI.create("http://localhost:8080")).build()
request ==> http://localhost:8080 GET

Don't forget build() when receiving with var



Configure HttpRequest

Use a builder to configure HttpRequest

jshell> var req2 = HttpRequest.newBuilder().

...> uri(URI.create("http://localhost:8080")).
...> timeout(java.time.Duration.ofMinutes(1)).
...> header("Content-Type", "application/x-www-form-urlencoded").
...> POST(HttpRequest.BodyPublishers.ofString(
...> "name=kishida&submit=ok")).
...> build()
req2 ==> http://localhost:8080 POST

Use BodyPublisher to send a post body



Send the request by using the client

jshell> var response = client.send(request, BodyHandlers.ofString())

response ==> (GET http://localhost:8080) 200

Import the static class with [shift]+[tab], [i]

jshell> var response = client.send(request, BodyHandlers

0: Do nothing
1: import: java.net.http.HttpResponse.BodyHandlers



HttpResponse will be returned

The type of the response is HttpResponse with a corresponding type to BodyHandler as a generic type

jshell> /v response

| HttpResponse<String> response = (GET http://localhost:8080) 200



Process the response

Getting the status code

jshell> response.statusCode()

$12 ==> 200



Process the response

Getting the response body

shell> response.body().lines().limit(5).forEach(System.out::println)

<html><head><title>Hello</title></head>
<body><h1>Hello</h1>
This is server<br>2018-10-20T10:32:26.120379</body></html>

lines() is a new API of String on JDK11



Asynchronous way

sendAsync returns CompletableFuture to process the request asynchronously

jshell> client.sendAsync(req, BodyHandlers.ofString())

$34 ==> jdk.internal.net.http.common.MinimalFuture@4e096385[Not completed] (id=100)

jshell> /vars $34
| CompletableFuture<HttpResponse<String>> $34 = jdk.internal.net.http.common.MinimalFuture@4e096385[Completed normally] (id=100)



Asyncronous way

thenApply or thenAccept to process a following procedures

jshell> $34.thenApply(HttpResponse::body)

$35 ==> jdk.internal.net.http.common.MinimalFuture@34f5090e[Completed normally] (id=143)

jshell> $35.thenAccept(System.out::println)
<html><head><title>Hello</title></head>
<body><h1>Hello</h1>
This is server<br>2018-10-22T12:20:52.580561</body></html>

$36 ==> jdk.internal.net.http.common.MinimalFuture@1cbb87f3[Completed normally] (id=144)



181: Nest-Based Access Control

Java has 4 visibilities


  • public

  • protected

  • default

  • private

But there is the 5th visibility



5th visibility

Nested private

We can use private members in a nestmates

class Outer {

class Inner {
private static foo;
}
int foo() {
return Inner.foo;
}
}



Nested is compiled into two independent class


  • Outer.class

  • Outer$Inner.class

Need to access Outer's private member from Outer$Inner

(Can't access Outer$Inner's private from even Outer)



Secret method is generated until JDK 10

jshell> Outer.Inner.class.getDeclaredMethods()

$8 ==> Method[1] { static int Outer$Inner.access$000() }



Peek Nestmates

Retrieving nestmates by getNestMembers()

jshell> HttpRequest.class.getNestMembers()

$18 ==> Class[4] {
class java.net.http.HttpRequest,
class java.net.http.HttpRequest$BodyPublishers,
interface java.net.http.HttpRequest$BodyPublisher,
interface java.net.http.HttpRequest$Builder }



Peek Nestmates

Retrieving nest host by getNestHost()

nest host: top level type of the nestmates

jshell> HttpRequest.Builder.class.getNestHost()

$19 ==> class java.net.http.HttpRequest



Peek Nestmates

Checking if a class is the nestmate

HttpRequest is a nestmate of HttpRequest.Builder

jshell> HttpRequest.class.isNestmateOf(HttpRequest.Builder.class)

$20 ==> true

HttpRequest is NOT a nestmate of String

jshell> HttpRequest.class.isNestmateOf(String.class)

$21 ==> false



Try to check nestmates

Class of Collectoin.empty()

jshell> Collections.emptyList().getClass().getNestMembers()



Try to check a defining class

jshell> class Outer { class Inner {} }

| created class Outer

jshell> Outer.class.getNestMembers()



Class defining in JShell

Class that is defined in JShell is defined as a nested class of the blank name class

jshell> Outer.class.getNestMembers()

$2 ==> Class[3] { class , class Outer, class Outer$Inner }



323: Local-Variable Syntax for Lambda Parameters

Allow to use var for lambda parameters

(var x, var y) -> x + y



Example

jshell> IntBinaryOperator op = (var x, var y) -> x + y

op ==> $Lambda$17/0x00000008000b2c40@1e88b3c



Every parameter must be var when using var

Can not mix var and non var

jshell> IntBinaryOperator ibo = (var x, y) -> x + y

| Error:
| invalid lambda parameter declaration
| (cannot mix 'var' and implicitly-typed parameters)
| IntBinaryOperator ibo = (var x, y) -> x + y;
| ^



Every parameter must be var when use var

Can not mix var and explicit type

jshell> IntBinaryOperator ibo = (var x, int y) -> x + y

| Error:
| invalid lambda parameter declaration
| (cannot mix 'var' and explicitly-typed parameters)
| IntBinaryOperator ibo = (var x, int y) -> x + y;
| ^



Need parenthesis

What will occur with this?

jshell> IntFunction f = var x -> x * 2



Need parenthesis

Need parenthesis even parameter is single

jshell> IntFunction f = var x -> x * 2

| Error:
| ';' expected
| IntFunction f = var x -> x * 2;
| ^

Put parethesis

jshell> IntFunction f = (var x) -> x * 2

f ==> $Lambda$18/0x00000008000b7040@5e3a8624



Is there anything good for using var on lambda parameters?

We can use annotation

(@Nullable var s) -> s + "!!!"

🤔🤔🤔



JDK11 APIs


  • String

  • I/O

  • Util



New in String


  • repeat(int)

  • isBlank()


  • strip() / stripLeading() / stripTrailing()

  • lines()

  • Character.toString(int)



repeat(int)

Repeat a string

jshell> "foo".repeat(3)

$38 ==> "foofoofoo"



isBlank()

Same as isEmpty() but treating UTF-8 whitespace as space

jshell> var fullspace = "\u3000"

fullspace ==> " "

jshell> fullspace.isEmpty()
$24 ==> false

jshell> fullspace.isBlank()
$25 ==> true



strip() / stripLeading() / stripTrailing()

Same as trim()/ trimLeft() / trimRight() but treating UTF-8 whitespace as space

jshell> var s = fullspace + "ttt" + fullspace

s ==> " ttt "

jshell> s.trim()
$41 ==> " ttt "

jshell> s.strip()
$42 ==> "ttt"

jshell> s.stripLeading()
$43 ==> "ttt "

jshell> s.stripTrailing()
$44 ==> " ttt"



lines()

Split a string to stream by \n

jshell> "abc\ndef\nghi".lines().count()

$18 ==> 3



Character.toString(int)


JDK10

jshell> Character.toString(65)

| Error:
| incompatible types: possible lossy conversion from int to char
| Character.toString(65)
| ^^


JDK11

jshell> Character.toString(65)

$15 ==> "A"



New in I/O


  • Path.of

  • Files

  • null I/O



Path.of

Paths.create until JDK10

Path.of since JDK11

Follow the recent convention to use of to factory method

jshell> var p = Path.of("hello.txt")

p ==> hello.txt



Files


  • writeString

  • readString



Files.writeString

Write string to a file

Files.writeString(Path, CharSequence, OpenOption...)

Files.writeString(Path, CharSequence, Charset, OpenOption...)

jshell> Files.writeString(p, "Hello")

$4 ==> hello.txt



Files.readStrig

Read a file content as string

Files.readString(Path)

Files.readString(Path, Charset)

jshell> Files.readString(p)

$5 ==> "Hello"



null I/O

Input nothing, output nothing like /dev/null


  • Reader.nullReader()

  • Writer.nullWriter()

  • InputStream.nullInputStream()

  • OutputStream.nullOutputStream()



null I/O example


Read

jshell> Reader.nullReader().read()

$13 ==> -1


Write

jshell> Writer.nullWriter().write("hello")




New in java.util


  • Collection.toArray(IntFunction)

  • Predicate.not(Predicate)

  • Optional.isEmpty()



Collection.toArray(IntFunction)

Until JDK10, need to specify the array size or receive Object array


JDK10

jshell> var list = List.of("aa", "bb")

list ==> [aa, bb]

jshell> list.toArray(new String[list.size()])
$46 ==> String[2] { "aa", "bb" }

jshell> list.toArray()
$47 ==> Object[2] { "aa", "bb" }




Collection.toArray(IntFunction)

We couldn't convert a list to a typed array with toArray on one-liner effectively

jshell> Collections.nCopies(new Random().nextInt(5), "a").toArray(new String[3]) 

$50 ==> String[4] { "a", "a", "a", "a" }

The prepared array is disposed



Collection.toArray(IntFunction)

The new API resolve the problem


JDK11

jshell> list.toArray(String[]::new)

$48 ==> String[2] { "aa", "bb" }



Predicate.not(Predicate)

We couldn't use a method reference when we need a negated condition so far

jshell> var strs = List.of("aa", "", "bb")

strs ==> [aa, , bb]

jshell> strs.stream().filter(s -> !s.isEmpty()).toArray()
$52 ==> Object[2] { "aa", "bb" }



Predicate.not(Predicate)

We can negate a condition with method reference at JDK11

jshell> import static java.util.function.Predicate.not

jshell> strs.stream().filter(not(String::isEmpty)).toArray()
$55 ==> Object[2] { "aa", "bb" }



Optional.isEmpty()

Optional has isPresent() so far

Negated condition isEmpty() is available on JDK11

jshell> Optional.empty().isEmpty()

$49 ==> true

OptionalInt and OptionalDouble have it also



Other change

Changed the message of ArrayIndexOutOfBoundsException

We couldn't understand what does the number mean


JDK10

jshell> (new int[0])[0]

| java.lang.ArrayIndexOutOfBoundsException thrown: 0
| at (#1:1)


JDK11

jshell> (new int[0])[0]

| Exception java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
| at (#26:1)



JDK12



JDK12 JEPs so far

2 JEPs related to writing codes


  • 326: Raw String Literals (Preview)

  • 325: Switch Expressions (Preview)



326: Raw String Literals (Preview)

Raw String Literals(RSL) make it easier to write a string literal with \n, \ and "

It can span multiple lines of code

var str = `

<head>
<title>Hello</title>
<meta name="robot" content="all">
</head>
`



Preview features is disabled by default

--enable-preview switch is required

jshell> `foo`

| Error:
| raw string literals are a preview feature and are disabled by default.
| (use --enable-preview to enable raw string literals)
| `foo`
| ^



Preview features is disabled by default

--enable-preview switch is required

oco2018 $ jshell --enable-preview

| Welcome to JShell -- Version 12-ea
| For an introduction type: /help intro

jshell> `test`
$1 ==> "test"



Including ` in a raw string

Use `to include in a raw string

jshell> ``select `name` from users``

$57 ==> "select `name` from users"



Support method for RSL

RSL will be include indentational spaces

jshell> var s = `

...> test
...> `
s ==> "\n test\n "



Support method for RSL

Two method is introduced to address an indentation in RSL


  • align(int)

  • indent(int)



align(int)

Remove horizontal and vertical margin with remaining a specified indentation

jshell> var s = `

...> test
...> test
...> `
s ==> "\n test\n test\n "

jshell> s.align()
$7 ==> "test\ntest\n"

The first blank line is removed



indent(int)

Adding a specified number of indentation spaces

jshell> `

...> test
...> test
...> `.indent(2)
$3 ==> "\n test\n test\n"



Raw string literal will be dropped from JDK12

😰😰😰

`` seems a blank string.

Quote character is rare. We can't use the backquote profligately.



325: Switch Expressions (Preview)

Extend switch statement



  • case can take multiple values

  • use -> for a single line

  • can be used as an expression (not implemented yet)

var s = switch (a) {

case 1, 2 -> "One or Two";
case 3 -> "Three";
};



Thank you