LoginSignup
10

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-10-22
1 / 94

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10