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