JavaOne – 55 new features in Java 9

“55 new features in Java 9”

Speaker: Simon Ritter

For more blog posts from JavaOne, see the table of contents


  • Modularity/Jigsaw – JDK is 94 moudles. Java SE is 36 of them. Probably using sun.misc.Unsafe in open source library
  • Big kill switch now has options to permit/warn/debug (warn with stack trace)/deny(will be default at some point) illegal access
  • jlink – jaa linker so can build runtime specifically for your application. Creates directory structure for you that matches jdk but only wit the modules you need. java -list-modules shows what modules are in there. Version numbering information is for informational purposes only. Can’t use different versions for different parts of the code.
  • Static factory methods for List/Set/Map interfaces. Old way was to instantiate, add a bunch of elements and then call Collections.unmodifiableSet(). Now can just call Set.of(…) with 0-10 elements or varargs if have more and get an umodifiable collection
  • Stream enhancements – dropWHile/takeWhile (like skip/limit but with predicate rather than number), improved iterate to be more like a for loop, parallel Files.lines() as memory mapped and a stream from Optional with zero/one elements
  • multi-release jar files – use JDK 8 code in main jar file and then JDK 9 in the “9” diretory
  • jshell – REPL (read eval print loop) – good for simple prototyping
  • concurrency updates – reactive streams publish/subscribe framework, async nonblocking, Flow interfaces, SubmissionPublisher utility class.
  • CompleteableFuture additions (originally added in Java 8). Now has delays/timeouts, better support fr subclassing, static utility methods for minimalCompletionStage (read JavaDoc; confusing), failedStage, failedFuture [and one more]
  • Enhanced deprecation – forRemoval and since (not back ported consistently), jdeprscan command can produce report from jar or class file
  • Project Coin – single underscore not valid identifier (so in future can use _ in lambda instead of variable), priate method in interfaces, effectively final variables in tr-with-resources, allow @SafeVarars on private instance variables, diamond operate with anonyous classes
  • New standards – Unicode 7 (2834 new chars) and 8 (7716 new chars) support – added emojis, PKCS12 key stores by default, HTML 5 JavaDoc, etc
  • UTF-8 property files
  • DRBG based SecureRadom bit generators
  • XML catalog API upgraded standard
  • G1 is default garbage collector for servers (used to be parallel collectors), low pause, deals with bigger heaps
  • Better String performance – compact strings (use less space internally; don’t use 16 bits for chars that could be 8 bits), store interned strings in CDS archive to share char[] and String objects between VMs, String concatentaton to use invokedynamic (allows for future performance improvements at runtim)
  • Marlin graphics renderer – faster
  • A couple really low level VM performance things
  • JavaFX improvement
  • Segment Code cache – separates non-method, proiled and non-profiled code (enables future performance improvments)
  • Unified JVM and GC logging – using old options prevent JVM startup
  • Spin-wait hints. Small change to improve performance on x86, but Azul [where Simon works] proposed it showing openness of JEP.
  • Variable handles – API to replace parts of sun.misc.Unsafe. Used for fence operations (memory control/atomic operations preventing JVM from changing order of operations in code), VarHandle (low level objec)
  • AOT compilation – ahead of time compilation – experimental feature; need to turn on with UnlockExperimenalVMOptions. jaotc to comiple in this mode
  • Process API can get pid, arguments, start time, CPU usage and name if security manager allows
  • New version string format for java JDK major minor security patch. Will cange again post Java 10. No more 1.X
  • JDK/JRE file structure – only one bin directory no special jre direcory. tools.jar and rt.jar also went away.
  • Sarchable JavaDocs
  • Annotation pipeline – repeating annotations
  • Parser API for Nashorn – and spports ECMAScript 5.1
  • Disable SHA-1 certs mostly
  • Applets deprecated for removal in Java 10
  • A handful of APIs removed [not ommon ones]
  • Removed a few other things like hprof agent, jhat tool, old docs
  • Removed deprecated GC options

My take: He said up front that this talk is supposed to be an hour. Implying we won’t get to all 55 features. He didn’t sound rushed though so there wasn’t the problem from yesterday’s speaker with two much information. It was a good overview (or review) of the features. I learned some things like the eixstance of jdeprscan

JavaOne – Make your CPU cores sweat with Parallel Streams

“Make your CPU cores sweat with Parallel Streams”

Speaker: Lukasz Pater

For more blog posts from JavaOne, see the table of contents


Started with the canonical Person/Car/age example to show what streams are [I think everyone at Javaone knows that]

Then showed code that finds all the prims under 10 milion that are palindromes when expressed in binary. Moores law is now relying on multi-core architecture. This example takes 1.6 seconds vs 8.6 seconds as parallel improvement. Five times faster.

Good analogy: If told to wash the fork, then the knife, then the… it is slow. If told to wash the dishes, you can optimize internally.

History of threads

  • JDK 1 – Threads – still good for small background task
  • JDK 5 – ExecutorService, concurrent objects
  • JDK 7 – fork/join framework – recursively decompose tasks into subtasks and then combine results
  • JDK 8 – parallel streams – use fork/join framework and Spliterator behind the scenes

Making a parallel stream

  • parallelStream() – for source
  • parallel() – anywhere in stream pipeline intermediate operation list

Fork Join Pool

  • Uses work stealing to balance tasks amongst workers in pool
  • All parallel streams use one common pool instance with # threads = # CPU cores – 1. That final thread is for the master to assign work.
  • Can change by setting system property java.util.concurrent.ForkJoinPool.common.parallelism. Must pass on commands line because first call to parallel stream resets it if set in code
  • If want custom fork join pool, create one and submit your stream to it. Does not recommend doing this. One reason you might want to is to add a timeout to the stream

Warnings

  • Avoid IO – burn CPU cycles waiting for IO/network
  • Use only for CPU intensive tasks
  • Be careful with nested paralle streams
  • Having many smaller tasks in the pool will better balance the workload
  • Don’t create your own fork join pool

Spliterator

  • splitable iterator
  • to traverse elements of a source in parallel
  • tryAdvance(Consumer) – do something if an element exists
  • trySplit() – partition off some elements to another spliterator leaving less elements in the original – fork so have tree of spliterators until run out of elements
  • characteristics()
  • estimateSize()
  • StreamSupport.stream(mySplierator, true) – creates parallel stream from spliterator – shouldn’t need to do this
  • ArrayList decomposes into equal sizes. LinkedList gives a smaller % of the elements because linear to get elements and want to minimize wait time
  • ArrayList and IntStream.range decompose well
  • LInkedLIst and Stream.iterate() decompose poorly – could even run out of memory
  • HashSet and TreeSet decompose in between

Other tips

  • Avoiding autoboxing also saves time. iterate() creates boxed objects where range() creates primitives
  • Parallel streams perform better where order doesn’t atter. findAny() or unordered().limit() [he missed the terminal operation in the limit example]
  • Avoid shared state
  • If have multiple calls to sequential() and parallel(), the last one wins and takes effect for the entire stream pipeline

My take:
Good discussion of performance and things to be beware of. My blog wasn’t live becase I couldn’t get internet in the room. I typed it live though! A couple typos like findFist() but nothing signficiant

JavaOne – Streams in JDK 8

“Streams in Java 8 – The good, the bad & the ugly”

Speaker: Simon Ritter & Stuart Marks
[Simon has the Twtter handle @speakjava; very cool]

For more blog posts from JavaOne, see the table of contents


Need to think differently. We are used to imperative programming with loops and variables.

Dealing wih exceptions
ugly code – three lines of code and hard to tell what it does

Problems:

  • looks like Perl
  • returns null (vs Optional or empty string)
  • split is called twice so wasted work
  • skipped URLDecoder.decode() because didn’t want to deal with a checked exception – but lost functionality. Problem caused by a missing API in Java so have to use decode.

Better approach:

  • use a method with a try/catch block; call that method from the stream
  • use Map.entry to simulate a tuple
  • Use single char (vs regex) in split. If only pass one character to split, far faster
  • split() is overloaded to take a numeric limit to how many are returned

Imperative streams
inside the for each is a print, and if statement and a LongAdder variable (good for frequent writes and infrequent reads)

then refactored to use mapToInt, a println and an if statement and a local variable. more complicated and still not functional

then switched to peek and no variabe but still an if statement (well a ternary)

finally switched to use a filter and count instead of sum

still not 100% functional because println is a side effect. ok for debugging

[good showing evolution to get functional]

Problems

  • Easy to misuse forEach() because feels familiar. But easily leads to side effects
  • Imperative thinking “for each of these I want to..”
  • Pause to consider if should use for each

Mixing internal and external iteration
for loop running 12 times and then getting data for each month with filter checking Month.of(x) – doesn’t work because x isn’t effectively final

“solve” effectively final by setting to different interim variable

IntStream.range(0,12).forEach – uses internal iteration but forEach. Marginaly better as don’t need interim variable

Instead return a nested map of Month to Map with nested grouping by so only need one iteration – the data stream

Problems

  • Going through data.stream() 12 times
  • forEach cheat
  • array not right data structure; it’s really a map of month to value

Hands on lab question
reduce (“”, (a,b) -> a+b) – works but inefficient because String concatenation

reduce(a,b) -> sb.append(b) – fails because ignores the first letter.

next attempt uses an if statement in reduce

then tried a custom collector. works but more complicated than necessary
Collector.of(StringBuilder::new, StringBuilder::append, StringBuilder::append, StringBuilder::toString

or just use Collectors.joining()

Problems

  • If not using a parameter, it is probably wrong
  • Side effects
  • if stateent version not associative so would fail when run in parallel

Misc

  • can’t use same stream multiple times
  • method references are slightly more efficient than lambdas because lambda gets added into a method in bytecode. Saves a level of indirection by using method reference. But only slightly
  • Calling .sorted() multiple times vs chaining comparing.thenComparing – the later is better [also works because preserves sort :)]
  • parallel streams do more work. might or might not complete faster. uses fork-join pool. number of threads defaults to number of CPUs. In Java9, this is # CPUs for container. On Jaa 8, it was for physical machine
  • Nested parallel streams is bad idea because using same threads so performance is worse. Can create ForkJoinPool if must. Buyer beware; this is an implementation specific behavior and tied to the profile of the machine you write it for.

My take: Fun start to he morning. I like that they covered common things in an entertaining way and not common things. Something to learn for everyone!