1. Start

PRINTING - imports static print functions

  • useful starting options at the begining
    • v - verbose
    • /set feedback verbose
    • PRINTING
      • show /list
>jshell
jshell> /exit

>jshell --start PRINTING -v

> /help
> /help intro

> /open PRINTING

simple expressions

//no semicolons
jshell> println("hello")

jshell> "hello"
$2 ==> "hello"
|  created scratch variable $2 : String

// use temporary variable
jshell> $2

//list temporary variables
jshell> /vars 
|    String $2 = "hello"

jshell> /v 

//manipulate temporary variables, [tab] auto completion
shell> $2.toUpperCase(
toUpperCase(   

jshell> $2.toUpperCase()
$4 ==> "HELLO"

//waits for completion
jshell> 2+
   ...> 2

jshell> String <tab> full doc
jshell> IntStream <tab> full doc


//Java 10
jshell> var i=1+1
i ==> 2
|  created variable i : int


jshell> var s="hello java 10"
s ==> "hello java 10"
|  replaced variable s : String
|    update overwrote variable s : Stream<Integer>

jshell> s.toUpperCase()
$12 ==> "HELLO JAVA 10"
|  created scratch variable $12 : String

docs

  • write simple function : i => i+1
  • hit tab two times
jshell> f.apply(
apply(   

jshell> f.apply(
$10   $11   $12   $27   $4    $7    $8    

Signatures:
R Function<T extends Object, R extends Object>.apply(T t)

<press tab again to see documentation>

creating methods

 void prn(String s){
      System.out.println(s);
 }

show options

  • /methods
  • /list
    • /drop 1
    • /list f
  • /vars
  • /types
  • /env
    • env --
    • --add-exports --add-modules --class-path --module-path
/edit 11
void prn(Object s){
      System.out.println(s);
 }

Forward reference - you can use variables before declaring them

 void action(Integer i){
   ...> prn(f2.apply(i));
   ...> }
|  created method action(Integer), however, it cannot be invoked until variable f is declared


jshell> MyClass mc
|  created variable mc, however, it cannot be referenced until class MyClass is declared
  • show execution before f is defined
  • define f - i->i+1
  • show execution after f is defined
imports
  • /imports
  • LocalTime - Shift+Tab shortcut
history
  • ctrl+r
  • /history
  • /-2
  • /!
feedback
  • /set feedback + <tab>
    • show with 2+2

Now lets practice a little bit with Java8s improvements to gain better intuition around JSHELL.

2. Functions

  • Declare simple function
  • Use /vars and / imports
  • Composition - andThen & compose
  • Primitive specialization
  • First look at streams

First of all check "/imports" : java.util.function.* is already there.

Then create simple function : Int => Int

Function<Integer,Integer> f=x->x+1
f.apply(1)

Check /vars

|    Function<Integer, Integer> f = $Lambda$22/422250493@64bfbc86
|    Integer $46 = 2

composition

jshell> f.andThen(i->i*3)
$2 ==> java.util.function.Function$$Lambda$16/346861221@46d56d67

jshell> $2.apply(1)

primitive specialization

IntUnaryOperator fi= x->x*2

ToIntFunction <tab> <tab>

No composition on ToInFunction :(

wrapper

jshell> IntUnaryOperator wi= i -> f.apply(i)
jshell> fi.andThen(wi)
$10 ==> java.util.function.IntUnaryOperator$$Lambda$20/1204167249@3e6fa38a
|  created scratch variable $10 : IntUnaryOperator

jshell> $10.applyAsInt(2)
$11 ==> 4
|  created scratch variable $11 : int

Streams "zajawka"

Int <tab>
IntPredicate
IntPredicate p=i->i>3
jshell> IntStream.range(0,15).filter(p).map(fi).toArray()
$9 ==> int[11] { 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28 }

3. Functional Interfaces

Till now we edited code directly in the REPL but sometimes it is easier to edit bigger piece of code in standard editor

/l
/edit 1

we will be able to edit given piece of code in JShell default editor. But if this is not enough - then we can set our own editor. Because of specific feature/bug : //https://bugs.openjdk.java.net/browse/JDK-8158738 we need to start new editor window in proper mode.

/set editor subl -wait
/set editor gedit -s
/set editor -default
Runnable
Runnable r=()->println("I'm in the run")
ExecutorService ec = Executors.newSingleThreadExecutor() // show variable creation
ec.submit(r)

Consumer<Object> prn=o->{
   ...> println(Thread.currentThread().getName()+":"+o);
   ...> }
/edit prn

prepare for editor

Consumer<Object> prn
prn ==> null
/edit 22
Comparator
Comparator<String> c = (s1,s2) -> s2.length() - s1.length()
List<String> l = Arrays.asList("aa","ccccccc","d")
l.sort(c)
l.stream().sorted(c).collect(Collectors.toList())
l.stream().sorted(c.reversed()).collect(Collectors.toList())

//try to sort java9 list.of..

Editor Modes

jshell> /set mode 
set jshell configuration information

<press tab again to see full documentation>

jshell> /set mode mine normal --command
|  Created new feedback mode: mine

jshell> /set prompt normal 
|  /set prompt normal "\njshell> " "   ...> "

jshell> /set prompt mine "jug>" ".....jug>"

jshell> /set feedback mine 
|  Feedback mode: mine
jug>class Jug{
.....jug>private String name="JUG";
.....jug>}
|  created class Jug

Return to previous settings

jug>/set feedback verbose 
|  Feedback mode: verbose

4. java.util.function

No let's practice JSHell a little bit on classes from java.util.function

  • predicate
  • supplier
  • consumer
  • specializations
Predicate
jshell> Predicate<Integer> moreThan5 = i -> i>5
jshell> IntPredicate moreThan5i = i -> i>5
jshell> Stream.iterate(1, i->i+3).filter(moreThan5).limit(3).collect(Collectors.toList())
jshell> IntStream.iterate(1, i->i+3).filter(moreThan5).limit(3).collect(Collectors.toList())
jshell> Stream.iterate(1, i->i+3).filter(moreThan5.and(i->i%2==0)).limit(3).collect(Collectors.toList())
$92 ==> [10, 16, 22]
  • show all methods with tab
  • show docs
Supplier
jshell> Supplier<Integer> supplyTwo = () -> 2
jshell> Supplier<Double> supplyRandom = Math::random

jshell> Stream.generate(supplyTwo).limit(4).collect(Collectors.toList())
$99 ==> [2, 2, 2, 2]

jshell> Stream.generate(supplyRandom).limit(4).collect(Collectors.toList())
$100 ==> [0.35414954082808403, 0.21393914765241107, 0.7805060407908487, 0.3950962664621315]

Create new class to show that parameterless constructor is also a supplier

jshell> class User{
   ...> public final String name="Roman";
   ...> public User(){
   ...> System.out.println("in the constructor : "+name);
   ...> }
   ...> }
|  created class User

jshell> Supplier<User> supplyUser=User::new

jshell> supplyUser.get()
in the constructor : Roman

now check this assignment

Function<String,User> s=User::new
|  Error:
|  incompatible types: invalid constructor reference
Editor
/l
(...)
 101 : class User{
       public final String name="Roman";
       public User(){
       System.out.println("in the constructor : "+name);
       }
       }
 102 : Supplier<User> supplyUser=User::new;
 103 : supplyUser.get()

/edit 101

jshell> Function<String,User> s=User::new
s ==> $Lambda$43/513169028@4d95d2a2
|  created variable s : Function<String, User>

jshell> s.apply("Stefan")
in the constructor : Stefan
Consumer
Consumer<String> p = System.out::println
jshell> /edit p
p ==> $Lambda$45/665372494@2d8f65a4
|  modified variable p : Consumer<Object>

jshell> p.accept("text")
text

Function Specializations

/set editor subl -wait

show -wait help

Unary Operator

jshell> UnaryOperator<String> up = s->s.toUpperCase()
jshell> UnaryOperator<String> up =  String::toUpperCase
jshell> up.apply("aaaa")
$3 ==> "AAAA"

Binary operator (less generics, more type safety but limited)

jshell> BinaryOperator<String> join=String::concat
jshell> join.apply("aaa","bbb")
$5 ==> "aaabbb"

Where to use it :

Stream.of("aa","bb","ccc").reduce(

Signatures:
T Stream<T extends Object>.reduce(T identity, BinaryOperator<T> accumulator)
jshell> Stream.of("aa","bb","ccc").reduce(join)
$6 ==> Optional[aabbccc]

other : ,BiPredicate,BiConsumer,BiFunction

5. JAVA 9

Collections constructors

  • list constructore
    • show new class type
  • set constructor
    • show exception in jshell
  • create a Map
    • create BiConsumer
jshell> List.of(1,2,3,4,5)
$9 ==> [1, 2, 3, 4, 5]

// show docs with tab
// show immutability

jshell> $9.getClass()
$12 ==> class java.util.ImmutableCollections$ListN

//show also all dedicated lists
//$3 ==> class java.util.ImmutableCollections$List1
//$4 ==> class java.util.ImmutableCollections$List2


jshell> Set.of(1,2,3)
$10 ==> [3, 2, 1]

jshell> Set.of(1,1,1)
|  java.lang.IllegalArgumentException thrown: duplicate element: 1
|        at ImmutableCollections$SetN.<init> (ImmutableCollections.java:462)
|        at Set.of (Set.java:501)
|        at (#11:1)

jshell> Map.of("k1",1,"k2",2)
$13 ==> {k2=2, k1=1}
//create BiConsumer

Stream improvements

  • stream takeWhile
    • show variant with generate(Math::rand)
  • stream dropWhile
    • use peek for debugging
    • never ending for infinite collections
    • create method with peek and Math::random
  • stream new iterate
jshell> /v
| List<Integer> $9 = [1, 2, 3, 4, 5]
jshell> $9.stream().takeWhile(i->i<3).toArray()
$15 ==> Object[2] { 1, 2 }

jshell> $9.stream().dropWhile(i->i<3).toArray()
$16 ==> Object[3] { 3, 4, 5 }


jshell> Stream.iterate(
Signatures:
Stream<T> Stream<T>.<T>iterate(T seed, UnaryOperator<T> f)
Stream<T> Stream<T>.<T>iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)


jshell> Stream.iterate(1, i->i<20, i->i+3).dropWhile(i->i<10).toArray()
$17 ==> Object[4] { 10, 13, 16, 19 }

jshell> $9.stream().peek(prn).dropWhile(i->i<3).toArray()
1
2
3
4
5
$53 ==> Object[3] { 3, 4, 5 }
  • Stream of Nullable
Stream.ofNullable(
Stream<T> Stream<T>.<T>ofNullable(T t)
Returns a sequential Stream containing a single element, if non-null, otherwise returns an
empty Stream .

jshell> Stream.of("aa",null,"bbb").flatMap(Stream::ofNullable).toArray()
$44 ==> Object[2] { "aa", "bbb" }
  • Iterate through map
    • can not reference top level function (JSHell magic)
    • BiConsumer case
/l
 13 : Map.of("k1",1,"k2",2)

jshell> Consumer<Object> prn=o->println(o)
jshell> $13.forEach(prn)
|  Error:
|  incompatible types: java.util.function.Consumer<java.lang.Object> cannot be converted to java.util.function.BiConsumer<? super java.lang.String,? super java.lang.Integer>
|  $13.forEach(prn)
|              ^-^

jshell> BiConsumer<Object,Object> prn2=(o1,o2) -> println(o1+"->"+o2)
jshell> $13.forEach(prn2)
k2->2
k1->1

Quick look : Modules

https://docs.oracle.com/javase/9/docs/api/java/lang/Module.html

jshell> $13.getClass()
$42 ==> class java.util.ImmutableCollections$MapN

jshell> $42.getModule()
$43 ==> module java.base

jshell> JShell  (Shift+Tab, then "i")
0: Do nothing
1: import: jdk.jshell.JShell

jshell> JShell.class.getModule()
$60 ==> module jdk.jshell

$39.getModule().getDescriptor().exports().stream().forEach(System.out::println)

jshell> JShell.class.getModule().getDescriptor().exports().stream().forEach(System.out::println)
jdk.jshell.spi
jdk.jshell.tool
jdk.jshell
jdk.jshell.execution

jshell> $48.getPackages().stream().filter(p->p.contains("lang")).toArray()
$50 ==> Object[6] { "java.lang.invoke", "java.lang.ref", "java.lang.reflect", "java.lang", "java.lang.annotation", "java.lang.module" }

private methods in interfaces

  • Explain default methods
  • /open PRINTING
  • open a file : jshellworkshop/DefaultMethods.jsh
/l
shows implementation

jshell> DefaultMethods1<String> dm = s -> s.length()
jshell> dm.andThen(i->i*2)
$48 ==> DefaultMethods1$$Lambda$36/110771485@86be70a

jshell> $48.app("aaa")
$49 ==> 6
  • private methods
jshell>  DefaultMethods2<String> dm = String::length
dm ==> $Lambda$37/2104545713@2a742aa2

jshell> dm.thenAdd(2).multiplyBy(3).app("aaa")
$51 ==> 15

Quick look : Try-with-resources-with-effective-final

  • Showtry.jsh

Optional

  • stream and ofNullable

  • flatMap

jshell> Stream.of(Optional.of(1),Optional.empty(),Optional.ofNullable(null),Optional.of(2)).
   ...> flatMap(Optional::stream).
   ...> toArray()
$64 ==> Object[2] { 1, 2 }
  • ifPresentOrElse
jshell> Optional<String> opt = Optional.of("hello") (Shit+Tab, later "v")

jshell> opt.ifPresentOrElse(
prn   

Signatures:
void Optional<T>.ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)

jshell> Consumer<String> onSuccess= s -> System.out.println(s.toUpperCase()))
jshell> Runnable onError= () -> System.out.println("FAIL")

jshell> opt.ifPresentOrElse(onSuccess,onError)
HELLO

jshell> opt.filter(s->s.length()>9).ifPresentOrElse(onSuccess,onError)
FAIL
  • Optional.or
jshell> Optional<String> sthElse = Optional.of("something else")

jshell> opt.filter(s->s.length()>9).or(() -> sthElse).ifPresentOrElse(onSuccess,onError)
SOMETHING ELSE

Futures

class Sleeper {

           static void sleep(int seconds){
               try{
                   TimeUnit.SECONDS.sleep(seconds);    
               }catch(InterruptedException e){}

           }
 }

 jshell> CompletableFuture.supplyAsync(()->{
   ...> Sleeper.sleep(1);
   ...> return 7;
   ...> })
$58 ==> java.util.concurrent.CompletableFuture@4e4aea35[Not completed]

CompletableFuture.copy

//Future on API side
jshell> CompletableFuture<String> cf = new CompletableFuture<String>()

jshell> CompletableFuture<String> forClient = cf.copy()
forClient ==> java.util.concurrent.CompletableFuture@5702b3b1[Not completed]

//client tries to complete future
jshell> forClient.complete("SURPRISE")
$7 ==> true

jshell> forClient
forClient ==> java.util.concurrent.CompletableFuture@5702b3b1[Completed normally]

//original not affected
jshell> cf
cf ==> java.util.concurrent.CompletableFuture@1ed4004b[Not completed, 1 dependents]


jshell> CompletableFuture<String> forClient2 = cf.copy()
forClient2 ==> java.util.concurrent.CompletableFuture@4bec1f0c[Not completed]

//API future completed
jshell> cf.complete("THIS WAS PLANNED")
$11 ==> true

jshell> cf
cf ==> java.util.concurrent.CompletableFuture@1ed4004b[Completed normally]


jshell> forClient
forClient ==> java.util.concurrent.CompletableFuture@5702b3b1[Completed normally]
//client affected
jshell> forClient2
forClient2 ==> java.util.concurrent.CompletableFuture@4bec1f0c[Completed normally]

HTTP/2 CLIENT

Add module

jshell> /env -add-modules jdk.incubator.httpclient
jshell> import jdk.incubator.http.*

create Handler :

jshell> HttpHandler
0: Do nothing
1: import: com.sun.net.httpserver.HttpHandler
Choice: 
Imported: com.sun.net.httpserver.HttpHandler

HttpHandler handler = he ->{
    String body="Simple server";
    he.sendResponseHeaders(200, body.length());
    try(OutputStream out = he.getResponseBody()){
        out.write(body.getBytes());
    }
}

start server

jshell> HttpServer
0: Do nothing
1: import: com.sun.net.httpserver.HttpServer
Choice: 
Imported: com.sun.net.httpserver.HttpServer

jshell> HttpServer server = HttpServer.create(new InetSocketAddress(8000),0)
jshell> server.createContext("/hello",handler)
jshell> server.start()

use new HTTP CLIENT

jshell> HttpClient client = HttpClient.newHttpClient()
jshell> URI uri = new URI("http://localhost:8000/hello")
jshell> HttpRequest req = HttpRequest.newBuilder().uri(uri).GET().build()
jshell> HttpResponse<String> response = client.send(req,HttpResponse.BodyHandler.asString())
jshell> response.body()

Finally Save session

jshell> /save -history backup.jsh

Stack Walker

StackWalker.getInstance().walk(s->s.collect(Collectors.toList()))

jshell> StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).walk(s->s.limit(3).collect(Collectors.toList()))
$18 ==> [do_it$(java:18), jdk.jshell/jdk.jshell.execution.DirectExecutionControl.invoke(DirectExecutionControl.java:209), jdk.jshell/jdk.jshell.execution.RemoteExecutionControl.invoke(RemoteExecutionControl.java:116)]

jshell> StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).walk(s->s.map(f->f.getDeclaringClass()).limit(7).collect(Collectors.toList()))
$23 ==> [class , class jdk.jshell.execution.DirectExecutionControl, class jdk.jshell.execution.RemoteExecutionControl, class jdk.jshell.execution.DirectExecutionControl, class jdk.jshell.execution.ExecutionControlForwarder, class jdk.jshell.execution.ExecutionControlForwarder, class jdk.jshell.execution.Util]

Process Handle

jshell> ProcessHandle.current().info().commandLine()
$24 ==> Optional[/usr/lib/jvm/jdk-9/bin/java -agentlib:jdwp=transport=dt_socket,address=localhost:41835 jdk.jshell.execution.RemoteExecutionControl 44626]

jshell> ProcessHandle.allProcesses().map(p->p.info().command()).collect(Collectors.toList())

jshell> new ProcessBuilder().command("sleep","2").start().toHandle().onExit().thenAccept(System.out::println)
$26 ==> java.util.concurrent.CompletableFuture@612679d6[Not completed]

jshell> 9147
jshell> ProcessBuilder jgrep = new ProcessBuilder().command("grep","jshell")
jshell> ProcessBuilder jsp = new ProcessBuilder().command("jps")
jsp ==> java.lang.ProcessBuilder@491cc5c9

jshell> ProcessBuilder.startPipeline(
Signatures:
List<Process> ProcessBuilder.startPipeline(List<ProcessBuilder> builders) throws IOException

6. Exercises

jshell> /open src/main/java/jug/lodz/workshop/jshellworkshop/exercises/

jshell> checkExercise1()
|  attempted to call method toUpper(String) which cannot be invoked until variable toUpperFunction is declared

results matching ""

    No results matching ""