In my last blog [1] I showed you how to invoke Nashorn, how to add a Java class and how to invoke a method on it. Now, we want to perform some queries on a bigger amount of data. You can find a description of this data structure on the free sample pages of my book “Java Lambdas and (parallel) Streams” [2]. You may download the sources of the data generator from source section of the associated web site [3].

ParallelStreams is a pure Maven project, which can be opened directly by NetBeans without any import. Compile this project because we need the resulting .jar file for our further investigations. If you prefer to use it without compiling, take it directly from my site [4].

If you want to use this jar (or your own jars), you need to add it to the classpath Nashorn uses to load Java classes from. This is done by adding the classpass option (-cp) whilst invoking Nashorn. Let’s assume, the jar is placed into the f:/temp folder:

c:/Program\ Files/Java/jdk1.8.0_74/bin/jjs.exe -cp f:/temp/ParallelStreams.jar

Next, load the Persons class.

var p = Java.type("de.muellerbruehl.parallelstreams.Persons")

This takes a while, because loading this class will generate the demo data too. As most Linux alike executables, jjs terminates when you press  {Ctrl+C}. If you want to copy and paste some code snippets, you have to use a special key combination or menu, depending on you operating system.   If you do not run jjs from the command line but within the NetBeans terminal window, use {Ctrl+Shift+C} to copy and {Ctrl+Shift+V} to insert text.

Once the demo data is generated, you can start interactively querying. Persons contains a static method getInstance() to get the single object of this class and a method getPersons() with a return type List<Person>.

var persons = p.getInstance()

Now, let’s get the size of this list. To print the size, we simply use the JavaScript print, which is much more simpler than loading Java’s system class.

print (persons.getPersons().size())

Next, we’ll test if we can get a stream and print out the element count. As before, the result should be 50000 again.

print (persons.getPersons().stream().count())

Now we want to test diverse filter or other stream operations. Within Java, this is done by using the Lambda operator. For example, if we want to filter for persons younger than 20 years, we would use

filter(p -> p.getAge() < 20)

which can also be written as

filter((p) -> p.getAge() < 20)

Remember this is a function which takes a parameter p. This is one person object of the stream. The function itself is defined right hand of the Lambda operator.

(If you don’t remember, I recommend to purchase my book “Java Lambdas and (parallel) Streams” [5]. You’ll get a more detailed explanation of Lambdas and Streams there.)

Since Nashorn is a JavaScript engine, we have to translate the Lambda expression into JavaScript. We need to rewrite filter((p) -> p.getAge() < 20) as filter(function(p) p.getAge() < 20). Knowing this, it’s easy to query the data.

print (persons.getPersons().stream().filter(function(p) p.getAge() < 20).count())

The following screen capture illustrates the session so far.

Interactive use of streams

Interactive use of streams

Now you can start exploring the new stream functions. Use NetBeans’ autocompletion feature to create some code, translate the Lambda operator it into its JavaScript pendant copy and paste the code into the terminal.

You might have recognized, that I omitted the semicolon at the end of a statement. Remember, we emulate a REPL by JavaScript! A line break will terminate the statement. Thus we can’t paste in formatted code like

print (persons.getPersons()
   .filter(function(p) p.isVendor())
   .flatMapToLong(function(p) p.getSelling().values()
       .stream().mapToLong(function(a) a.getQuantity()))

The code we paste in has to be a single line (although displayed here as a couple of lines, it must be a long one).

print (persons.getPersons().parallelStream().filter(function(p) p.isVendor()).flatMapToLong(function(p) p.getSelling().values().stream().mapToLong(function(a) a.getQuantity())).sum())

Like in Java, you may assign intermediate results to one or more variables (two lines of code).

var vendors = persons.getPersons().parallelStream().filter(function(p) p.isVendor())

print (vendors.flatMapToLong(function(p) p.getSelling().values().stream().mapToLong(function(a) a.getQuantity())).sum())

You may use the JavaScript engine Nashorn for a kind of Read-Eval-Print-Loop (REPL). As a harmful fact, you need a partial translation of your code into JavaScript. A line break can’t be used to structure the lines.

Beside that, it is a technique to explore some Java features interactively with productive Java versions.

But, upcoming Java 9 offers a real interactive Java shell. Although not released yet, you can use it for testing purpose. I’m going to write about this in my final part of this series.

Stay tuned!