Showing posts with label java9. Show all posts
Showing posts with label java9. Show all posts

Sunday, February 25, 2018

Java 9: Enhancements to the Process API

Java 9 brings various improvements to the Process API, used for controlling and managing operating system processes.

Getting information about a process

There is a new ProcessHandle class which provides the process's pid, parent and descendants, as well as information about the start time and accumulated CPU time.

jshell> Process p = new ProcessBuilder("stress", "--cpu", "4", "--timeout", "5").start();
p ==> Process[pid=5572, exitValue="not exited"]

jshell> p.pid()
$2 ==> 5572

jshell> p.info().user()
$3 ==> Optional[fahd]

jshell> p.info().command()
$4 ==> Optional[/usr/bin/stress]

jshell> p.info().commandLine()
$5 ==> Optional[/usr/bin/stress --cpu 4 --timeout 120]

jshell> Arrays.toString(p.info().arguments().get())
$6 ==> "[--cpu, 4, --timeout, 120]"

jshell> p.info().startInstant()
$7 ==> Optional[2018-02-25T16:38:56.742Z]

jshell> p.info().totalCpuDuration().get().toMillis()
$8 ==> 0

It's strange that totalCpuDuration always returns 0 (a duration string of "PT0S"), no matter what command I run.

Note that I am invoking the Linux stress command in the example above. This is a useful tool for imposing a certain type of stress (e.g. creating cpu load) on your system.

Listing all running processes

The static ProcessHandle.allProcesses() method returns a stream of all processes visible to the current process.

ProcessHandle.allProcesses()
             .map(ProcessHandle::info)
             .map(ProcessHandle.Info::commandLine)
             .flatMap(Optional::stream)
             .forEach(System.out::println)

Triggering a function when a process exits

The Process.onExit method can be used to schedule a function when a process terminates. This method returns a CompletableFuture, which contains a variety of methods that can be called to schedule functions. Here is an example:

Process proc = new ProcessBuilder("sleep", "10").start();
proc.onExit()
    .thenAccept(p -> System.out.println("Process " + p.pid() + " exited with " + p.exitValue()));

Alternatively, to wait for a process to terminate, you can call Process.onExit().get().

Tuesday, December 26, 2017

Java 9: JShell

JShell is a new tool introduced in Java 9 that evaluates Java statements entered on the command line. It is the first offical REPL (Read-Evaluate-Print Loop) implementation for the Java platform, and it is great for trying out Java code without having to fire up an IDE or write a full program!

To run JShell, simply type jshell on the command line. Obviously, make sure that you have installed JDK 9 and that your JAVA_HOME environment variable is set correctly. You will see a prompt like this:

$ jshell
|  Welcome to JShell -- Version 9
|  For an introduction type: /help intro

jshell>

Type /help at the prompt to see a list of available commands. To exit, type /exit.

You can enter code "snippets" and JShell will output the results. For example:

jshell> System.out.println("Hello World")
Hello World

You can auto-complete statements and also look at documentation using the Tab key:

jshell> System.out.
append(        checkError()   close()        equals(        flush()        format(        getClass()     hashCode()     notify()
notifyAll()    print(         printf(        println(       toString()     wait(          write(

Here is a screencast GIF showing JShell in action, created using LICECap:

Monday, December 25, 2017

Java 9: Enhancements to the Stream API

Java 9 adds 4 new methods to the Stream interface:

1. dropWhile

The dropWhile method is similar to the skip method but uses a Predicate instead of a fixed integer value. It drops elements from the input stream while the Predicate is true. All remaining elements are then passed to the output stream. For example:

IntStream.range(0, 10)
         .dropWhile(i -> i < 5)
         .forEach(System.out::println);
// prints 5, 6, 7, 8, 9

2. takeWhile

The takeWhile method is similar to the limit method. It takes elements from the input stream and passes them to the output stream while the Predicate is true. For example:

IntStream.range(0, 10)
         .takeWhile(i -> i < 5)
         .forEach(System.out::println);
// prints 0, 1, 2, 3, 4
Note: Be careful when using dropWhile and takeWhile when you have an unordered stream because you might get elements in the output stream that you don't expect.

3. ofNullable

The ofNullable method returns an empty stream if the element is null, or a single-element stream if non-null. This eliminates the need for a null check before constructing a stream.

Stream.ofNullable(null).count();  // prints 0
Stream.ofNullable("foo").count(); // prints 1

4. iterate

The static iterate method has been overloaded in Java 9 to allow you to create a stream using the for-loop syntax. For example:

Stream.iterate(0, i -> i < 10, i -> i + 1)
      .forEach(System.out::println); //prints from 0 to 9

Java 9: Enhancements to Optional

Previously, I wrote about the Optional class that was introduced in Java 8 to model potentially absent values and reduce the number of places where a NullPointerException could be thrown.

Java 9 adds three new methods to Optional:

1. ifPresentOrElse

The new ifPresentOrElse method allows you to perform one action if the Optional is present and a different action if the Optional is not present. For example:

lookup(userId).ifPresentOrElse(this::displayUserDetails,
                               this::displayError)

2. stream

The new stream method makes it easier to convert a stream of Optional objects into a stream of values that are present in them. Previously (in Java 8), you needed two steps in order to achive this. First, you would filter out the empty Optionals and then you would unbox the rest in order to get their values. This is shown below:

// In Java 8:
Stream.of("alice", "bob", "charles")
      .map(UserDirectory::lookup)
      .filter(Optional::isPresent)
      .map(Optional::get)
      .collect(toList());

In Java 9, the code becomes simpler using the stream method:

// In Java 9:
Stream.of("alice", "bob", "charles")
      .map(UserDirectory::lookup)
      .flatMap(Optional::stream)
      .collect(toList());

3. or

The or method is somewhat similar to the orElseGet method but returns Optional objects instead of values. If a value is present, it returns the existing Optional. If the value is not present, it returns the Optional produced by the supplying function. For example:

lookup(userId).or(() -> lookupInAnotherDatabase(userId));

Sunday, October 08, 2017

Java 9: My favourite feature!

First of all, sorry about the "click-baity" title!

My favourite feature in Java 9 has to be the Javadoc Search.

The Java API documentation now has a search box which you can use to find packages, types and methods quickly. It would be nice if it supported regular expressions :)

Here is a screencast GIF showing the Javadoc Search in action, created using LICECap:

Sunday, October 01, 2017

Java 9: Creating Immutable Collections

Static factory methods have been added in JDK 9, to allow you to easily create immutable lists, sets and maps.

Immutable Lists

Use the List.of() static factory methods to create immutable lists.

// in JDK 9
List<String> list = List.of("foo", "bar");

// in JDK 8
List<String> list2 = Collections.unmodifiableList(Arrays.asList("foo", "bar"));

// in Guava
List<String> list3 = ImmutableList.of("foo", "bar");

Immutable Sets

Use the Set.of() static factory methods to create immutable sets.

// in JDK 9
Set<String> set = Set.of("foo", "bar");

// in JDK 8
Set<String> set2 = Collections.unmodifiableSet(
                       new HashSet<>(Arrays.asList("foo", "bar")));

// in Guava
Set<String> set3 = ImmutableSet.of("foo", "bar");

Immutable Maps

Use the Map.of() and Map.ofEntries() static factory methods to create immutable maps.

// in JDK 9
Map<String, Integer> map = Map.of("key1", 1, "key2", 2);
// for more than 10 key-value pairs, use Map.ofEntries
Map<String, Integer> map2 = Map.ofEntries(entry("key1", 1),
                                          entry("key2", 2));

// in JDK 8
Map<String, Integer> map3 = new HashMap<>();
map3.put("key1", 1);
map3.put("key2", 2);
map3 = Collections.unmodifiableMap(map3);

// in Guava
Map<String, Integer> map4 = ImmutableMap.of("key1", 1, "key2", 2);
// or, for more than 5 key-value pairs:
Map<String, Integer> map5 = ImmutableMap.<String, Integer>builder()
                                .put("key1", 1)
                                .put("key2", 2)
                                .build();

Implementation Details

It's interesting to look at the implementation of these static factory methods. They return a different class based on which method you use e.g. if you call List.of(e1) you get an instance of ImmutableCollections.List1 but if you call List.of(e1, e2) you get an instance of ImmutableCollections.List2. These are compact field-based classes that consume less heap space than their unmodifiable (or mutable) equivalents.

Note that the immutable collections returned by the static factory methods are not "wrapper" collections like those returned by Collections.unmodifiable. With an unmodifiable collection, you can still modify the underlying collection if you have a reference to it, but an immutable collection will always throw an exception if you try to modify it.

Java 9: Eclipse Installation

Java 9 is out! This post shows you how to get developing with Java 9 in Eclipse straightaway!

  1. Install JDK 9
  2. Install Eclipse Oxygen
  3. Install Java 9 Support for Oxygen in Eclipse
  4. Finally, go to "Window > Preferences > Java > Installed JREs" in Eclipse and add your Java 9 JRE

That's it!

Update (14-Oct-2017): Eclipse Oxygen.1a (4.7.1a) supports Java 9, so the "Java 9 Support for Oxygen" plugin is no longer required.