JUnit Pioneer Presentation Slides

Posted on March 05, 2021 by Scott Leberknight

Recently I've been using JUnit Pioneer, which is an extension library for JUnit Jupiter (JUnit 5). It contains a lot of useful annotations that are really easy to use in tests, for example to generate a range of numbers for input into a parameterized test. This is a presentation about Pioneer that I gave on March 4, 2021.

JUnit Pioneer from Scott Leberknight

In case the embedded slideshow doesn’t work properly here is a link to the slides (opens in a new window/tab).

Unit Testing Presentation Slides

Posted on July 10, 2019 by Scott Leberknight

We have several interns this summer, and each Friday we're doing a short presentation on a different software development topic. On June 28, I gave a short presentation on (unit) testing. This presentation is very light on code, and heavier on philosophy. I shared the slides on SlideShare and have embedded them below.

Unit Testing from Scott Leberknight

In case the embedded slideshow doesn’t work properly here is a link to the slides (opens in a new window/tab).

SDKMAN! Presentation Slides

Posted on April 07, 2019 by Scott Leberknight

I’ve been using SDKMAN! for a while now to make it really easy to install and manage multiple versions of various SDKs like Java, Kotlin, Groovy, and so on. I recently gave a mini-talk on SDKMAN! and have embedded the slides below.

SDKMAN! from Scott Leberknight

In case the embedded slideshow doesn’t work properly here is a link to the slides (opens in a new window/tab).

JUnit 5 Presentation Slides

Posted on August 13, 2018 by Scott Leberknight

I just gave a short presentation on JUnit 5 at my company, Fortitude Technologies. JUnit 5 adds a bunch of useful features for developer testing such as parameterized tests, a more flexible extension model, and a lot more. Plus, it aims to provide a more clean separation between the testing platform that IDEs and build tools like Maven and Gradle use, versus the developer testing APIs. It also provides an easy migration path from JUnit 4 (or earlier) by letting you run JUnit 3, 4, and 5 tests in the same propject. Here are the slides:

JUnit 5 from Scott Leberknight

In case the embedded slide show does not display properly, here is a link to the slides on Slideshare. The sample code for the presentation is on GitHub here.

Process API Improvements in JDK9

Posted on April 04, 2017 by Scott Leberknight

Over the past year, several microservices I have worked on responded to specific events and then executed native OS processes, for example launching custom C++ applications, Python scripts, etc. In addition to simply launching processes, those services also needed to obtain information for executing processes upon request, or shut down processes upon receiving shut down events. A lot of what the services were doing was controlling native processes in response to specific external events, whether via JMS queues, Kafka topics, or even XML files dropped in specific directories.

Since the microservices were implemented in Java, I had to use the less-than-stellar Process API, which provides only the most basic support. Even though a few additional features were added in Java 8 - such as being able to check if a process is alive using Process#isAlive and waiting for process exit with a timeout - you still cannot obtain a handle to a running process by its process ID nor can you even get the process ID of a Process object. As a result of the limitations I wrote a bunch of utilities that basically call out to native programs like grep and pgrep to gather information on running processes, child processes for a specific process ID, and so on. Even worse, to simply find the process ID for a Process instance I used reflection to directly access the private pid field in the java.lang.UNIXProcess class (which first required checking that we were actually dealing with a UNIXProcess instance, by comparing the class name as a string, since UNIXProcess is package-private and thus you cannot obtain its Class instance).

Most people writing and talking about Java 9 are excited about things like the new module system in Project Jigsaw; the Java shell/REPL; the HTTP/2 client; convenience factory methods for collections; and so on. But I am maybe even more excited about the process API improvements, since it means I can get rid of a lot of the hackery I used to obtain process information. Some of the information you can now obtain from a Process instance includes:

  • Whether the process supports normal termination (i.e. any of the "non-forcible" kill signals in Linux)
  • The process ID (i.e. the "pid"), and yes it's about time
  • A handle to the current process
  • A handle to the parent process, if one exists
  • A stream of handles to the direct children of the process
  • A stream of handles to the descendants (direct children, their children, and so on recursively)
  • A stream of handles to all processes visible to the current process
  • Process metadata such as the full command line, arguments, start instant, owning user, and total CPU duration

For example, to obtain the process ID (written as a unit test, and using AssertJ assertions):

@Test
public void getPid() throws IOException {
    ProcessBuilder builder = new ProcessBuilder("/bin/sleep", "5");
    Process proc = builder.start();
    assertThat(proc.getPid()).isGreaterThan(0);
}

Or, to obtain all sorts of different process metadata using ProcessHandle (which is also new in JDK 9 via the info() method in Process):

@Test
public void processInfo() throws IOException {
    ProcessBuilder builder = new ProcessBuilder("/bin/sleep", "5");
    Process proc = builder.start();
    ProcessHandle.Info info = proc.info();
    assertThat(info.arguments().orElse(new String[] {})).containsExactly("5");
    assertThat(info.command().orElse(null)).isEqualTo("/bin/sleep");
    assertThat(info.commandLine().orElse(null)).isEqualTo("/bin/sleep 5");
    assertThat(info.user().orElse(null)).isEqualTo(System.getProperty("user.name"));
    assertThat(info.startInstant().orElse(null)).isLessThanOrEqualTo(Instant.now());
}

Note in the above test that every method in the ProcessHandle.Info returns an Optional, which is the reason for the orElse in the assertions. Another thing that I really needed - and thankfully JDK 9 now provides - is the ability to get a handle to an existing process by its process ID using the ProcessHandle#of method. Here is a simple example as a unit test:

@Test
public void getProcessHandleForExistingProcess() throws IOException {
    ProcessBuilder builder = new ProcessBuilder("/bin/sleep", "5");
    Process proc = builder.start();
    long pid = proc.getPid();

    ProcessHandle handle = ProcessHandle.of(pid).orElseThrow(IllegalStateException::new);
    assertThat(handle.getPid()).isEqualTo(pid);
    assertThat(handle.info().commandLine().orElse(null)).isEqualTo("/bin/sleep 5");
}

As with the ProcessHandle.Info methods, ProcessHandle#of returns an Optional so again that is the reason for the orElseThrow. In a real application you might take some other action if the returned Optional is empty, or maybe you just throw an exception as the above test does.

As a last example, here is a test that launches a sleep process, then streams all visible processes and finds the launched sleep process:

@Test
public void allProcesses() throws IOException {
    ProcessBuilder builder = new ProcessBuilder("/bin/sleep", "5");
    builder.start();

    String sleep = ProcessHandle.allProcesses()
            .map(handle -> handle.info().command().orElse(String.valueOf(handle.getPid())))
            .filter(cmd -> cmd.equals("/bin/sleep"))
            .findFirst()
            .orElse(null);
    assertThat(sleep).isNotNull();
}

In the above test, since allProcesses returns a Stream we can use normal Java 8 stream API features like map, filter, and so on. In this example, we first map (transform) the ProcessHandle to the command (i.e. "sleep") or the process ID if the command Optional is empty. Next we filter on whether the command equals /bin/sleep and call findFirst which returns an Optional, and finally use orElse to return null if the returned Optional was empty. Of course the above test can fail if, for example, there already happens to be a /bin/sleep 5 process executing in the operating system but we won't really worry about that here.

One last piece of information that might be needed is the current process, i.e. a process needs get a handle to its own process. You can now accomplish this easily by calling ProcessHandle.current(). The Javadoc notes that you cannot use the returned handle to destroy the current process, and says to use System#exit instead.

In addition to the process information shown in the above examples, there is also a new onExit method that returns a CompletableFuture that "provides the ability to trigger dependent functions or actions that may be run synchronously or asynchronously upon process termination" according to the Javadoc. The following example shows an example that uses the native cmp program to compare two files, and upon exit applies a lambda expression to check whether the exit value is zero (meaning the two files are identical). Finally, it uses the Future#get method with a 1 second timeout (to avoid blocking indefinitely) to obtain the result:

Process proc = new ProcessBuilder("/usr/bin/cmp", "/tmp/file1.txt", "/tmp/file2.txt").start();
Future<Boolean> areIdentical = proc.onExit().thenApply(proc1 -> proc1.exitValue() == 0);
if (areIdentical.get(1, TimeUnit.SECONDS)) { ... }

So a big thanks to the Java team at Oracle (I can't believe I just thanked Oracle) for adding these new features! In the "real world" where systems are heterogenous and need to integrate in myriad ways, having a much more featureful and robust process API helps a lot for any system that needs to launch, monitor, and destroy native processes.

AWS Lambda Presentation Slides

Posted on March 20, 2017 by Scott Leberknight

A few months ago I gave a short presentation to my company on AWS Lambda, which is basically a "serverless" framework that lets you deploy and run code in Amazon's cloud without managing, provisioning, or administering any servers whatsoever. Here are the slides:

AWS Lambda from Scott Leberknight

Testing HTTP Clients Using Spark, Revisited

Posted on March 14, 2017 by Scott Leberknight

In a previous post I described the very small sparkjava-testing library I created to make it really simple to test HTTP client code using the Spark micro-framework. It is basically one simple JUnit 4 rule (SparkServerRule) that spins up a Spark HTTP server before tests run, and shuts it down once tests have executed. It can be used either as a @ClassRule or as a @Rule. Using @ClassRule is normally what you want to do, which starts an HTTP server before any tests has run, and shuts it down afer all tests have finished.

In that post I mentioned that I needed to do an "incredibly awful hack" to reset the Spark HTTP server to non-secure mode so that, if tests run securely using a test keystore, other tests can also run either non-secure or secure, possibly with a different keystore. I also said the reason I did that was because "there is no way I found to easily reset security". The reason for all that nonsense was because I was using the static methods on the Spark class such as port, secure, get, post, and so on. Using the static methods also implies only one server instance across all tests, which is also not so great.

Well, it turns out I didn't really dig deep enough into Spark's features, because there is a really simple way to spin up separate and independent Spark server instances. You simply use the Service#ignite method to return an instance of Service. You then configure the Service however you want, e.g. change the port, add routes, filters, set the server to run securely, etc. Here's an example:

Service http = Service.ignite();
http.port(56789);
http.get("/hello", (req, resp) -> "Hello, Spark service!");

So now you can create as many servers as you want. This is exactly what is needed for the SparkServerRule, which has been refactored to use Spark#ignite to get separate servers for each test. It now has only one constructor which takes a ServiceInitializer and can be used to do whatever configuration you need, add routes, filters, etc. Since ServiceInitializer is a @FunctionalInterface you can simply supply a lambda expression, which makes it cleaner. Here is a simple example:

@ClassRule
public static final SparkServerRule SPARK_SERVER = new SparkServerRule(http -> {
    http.get("/ping", (request, response) -> "pong");
    http.get("/health", (request, response) -> "healthy");
});

This is a rule that, before any test is run, spins up a Spark server on the default port 4567 with two GET routes, and shuts the server down after all tests have completed. To do things like change the port and IP address in addition to adding routes, you just call the appropriate methods on the Service instance (in the example above, the http object passed to the lambda). Here's an example:

@ClassRule
public static final SparkServerRule SPARK_SERVER = new SparkServerRule(https -> {
    https.ipAddress("127.0.0.1");
    https.port(56789);
    URL resource = Resources.getResource("sample-keystore.jks");
    https.secure(resource.getFile(), "password", null, null);
    https.get("/ping", (request, response) -> "pong");
    https.get("/health", (request, response) -> "healthy");
});

In this example, tests will be able to access a server with two secure (https) endpoints at IP 127.0.0.1 on port 56789. So that's it. On the off chance someone was actually using this rule other than me, the migration path is really simple. You just need to configure the Service instance passed in the SparkServerRule constructor as shown above. Now, each server is totally independent which allows tests to run in parallel (assuming they're on different ports). And better, I was able to remove the hack where I used reflection to go under the covers of Spark and manipulate fields, etc. So, test away on that HTTP client code!

This blog was originally published on the Fortitude Technologies blog here.

Testing HTTP Clients Using the Spark Micro Framework

Posted on December 07, 2016 by Scott Leberknight

Testing HTTP client code can be a hassle. Your tests either need to run against a live HTTP server, or you somehow need to figure out how to send mock requests which is generally not easy in most libraries that I have used. The tests should also be fast, meaning you need a lightweight server that starts and stops quickly. Spinning up heavyweight web or application servers, or relying on a specialized test server, is generally error-prone, adds complexity and slows tests down. In projects I'm working on lately we are using Dropwizard, which provides first class testing support for testing JAX-RS resources and clients as JUnit rules. For example, it provides DropwizardClientRule, a JUnit rule that lets you implement JAX-RS resources as test doubles and starts and stops a simple Dropwizard application containing those resources. This works great if you are already using Dropwizard, but if not then a great alternative is Spark. Even if you are using Dropwizard, Spark can still work well as a test HTTP server.

Spark is self-described as a "micro framework for creating web applications in Java 8 with minimal effort". You can create the steroptypical "Hello World" in Spark like this (shamelessly copied from Spark's web site):

import static spark.Spark.get;

public class HelloWorld {
    public static void main(String[] args) {
        get("/hello", (req, res) -> "Hello World");
    }
}

You can run this code and visit http://localhost:4567 in a browser or using a client tool like curl or httpie. Spark is a perfect fit for creating HTTP servers in tests (whether you call them unit tests, integration tests or something else is up to you, I will just call them tests here). I have created a very simple library sparkjava-testing that contains a JUnit rule for spinning up a Spark server for functional testing of HTTP clients. This library consists of one JUnit rule, the SparkServerRule. You can annotate this rule with @ClassRule or just @Rule. Using @ClassRule will start a Spark server one time before any test is run. Then your tests run, making requests to the HTTP server, and finally once all tests have finished the server is shut down. If you need true isolation between every single test, annotate the rule with @Rule and a test Spark server will be started before each test and shut down after each test, meaning each test runs against a fresh server. (The SparkServerRule is a JUnit 4 rule mainly because JUnit 5 is still in milestone releases, and because I have not actually used JUnit 5.)

To declare a class rule with a test Spark server with two endpoints, you can do this:

@ClassRule
public static final SparkServerRule SPARK_SERVER = new SparkServerRule(() -> {
    get("/ping", (request, response) -> "pong");
    get("/healthcheck", (request, response) -> "healthy");
});

The SparkServerRule constructor takes a Runnable which define the routes the server should respond to. In this example there are two HTTP GET routes, /ping and /healthcheck. You can of course implement the other HTTP verbs such as POST and PUT. You can then write tests using whatever client library you want. Here is an example test using a JAX-RS:

@Test
public void testSparkServerRule_HealthcheckRequest() {
    client = ClientBuilder.newBuilder().build();
    Response response = client.target(URI.create("http://localhost:4567/healthcheck"))
            .request()
            .get();
    assertThat(response.getStatus()).isEqualTo(200);
    assertThat(response.readEntity(String.class)).isEqualTo("healthy");
}

In the above test, client is a JAX-RS Client instance (it is an instance variable which is closed after each test). I'm using AssertJ assertions in this test. The main thing to note is that your client code be parameterizable, so that the local Spark server URI can be injected instead of the actual production URI. When using the JAX-RS client as in this example, this means you need to be able to supply the test server URI to the Client#target method. Spark runs on port 4567 by default, so the client in the test uses that port.

The SparkServerRule has two other constructors: one that accepts a port in addition to the routes, and another that takes a SparkInitializer. To start the test server on a different port, you can do this:

@ClassRule
public static final SparkServerRule SPARK_SERVER = new SparkServerRule(6543, () -> {
    get("/ping", (request, response) -> "pong");
    get("/healthcheck", (request, response) -> "healthy");
});

You can use the constuctor that takes a SparkInitializer to customize the Spark server, for example in addition to changing the port you can also set the IP address and make the server secure. The SparkInitializer is an @FunctionalInterface with one method init(), so you can use a lambda expression. For example:

@ClassRule
public static final SparkServerRule SPARK_SERVER = new SparkServerRule(
        () -> {
            Spark.ipAddress("127.0.0.1");
            Spark.port(9876);
            URL resource = Resources.getResource("sample-keystore.jks");
            String file = resource.getFile();
            Spark.secure(file, "password", null, null);
        },
        () -> {
            get("/ping", (request, response) -> "pong");
            get("/healthcheck", (request, response) -> "healthy");
        });

The first argument is the initializer. It sets the IP address and port, and then loads a sample keystore and calls the Spark#secure method to make the test sever accept HTTPS connections using a sample keystore. You might want to customize settings if running tests in parallel, specifically the port, to ensure parallel tests do not encounter port conflicts.

The last thing to note is that SparkServerRule resets the port, IP address, and secure settings to the default values (4567, 0.0.0.0, and non-secure, respectively) when it shuts down the Spark server. If you use the SparkInitializer to customize other settings (for example the server thread pool, static file location, before/after filters, etc.) those will not be reset, as they are not currently supported by SparkServerRule. Last, resetting to non-secure mode required an incredibly awful hack because there is no way I found to easily reset security - you cannot just pass in a bunch of null values to the Spark#secure method as it will throw an exception, and there is no unsecure method probably because the server was not intended to set and reset things a bunch of times like we want to do in test scenarios. If you're interested, go look at the code for the SparkServerRule in the sparkjava-testing repository, but prepare thyself and get some cleaning supplies ready to wash away the dirty feeling you're sure to have after seeing it.

The ability to use SparkServerRule to quickly and easily setup test HTTP servers, along with the ability to customize the port, IP address, and run securely intests has worked very well for my testing needs thus far. Note that unlike the above toy examples, you can implement more complicated logic in the routes, for example to return a 200 or a 404 for a GET request depending on a path parameter or request parameter value. But at the same time, don't implement extremely complex logic either. Most times I simply create separate routes when I need the test server to behave differently, for example to test various error conditions. Or, I might even choose to implement separate JUnit test classes for different server endpoints, so that each test focuses on only one endpoint and its various success and failure conditions. As is many times the case, the context will determine the best way to implement your tests. Happy testing!

This blog was originally published on the Fortitude Technologies blog here.

Towards More Functional Java - Digging into Nested Data Structures

Posted on November 14, 2016 by Scott Leberknight

In the last post we saw an example that used a generator combined with a filter to find the first available port in a specific range. It returned an Optional to model the case when no open ports are found, as opposed to returning null. In this example, we'll look at how to use Java 8 streams to dig into a nested data structure and find objects of a specific type. We'll use map and filter operations on the stream, and also introduce a new concept, the flat-map.

In the original, pre-Java 8 code that I was working on in a project, the data structure was a three-level nested structure that was marshaled into Java objects from an XML file based on a schema from an external web service. The method needed to find objects of a specific type at the bottom level. For this article, to keep things simple we will work with a simple class structure in which class A contains a collection of class B, and B contains a collection of class C. The C class is a base class, and there are several subclasses C1, C2, and C3. In pseudo-code the classes look like:

class A {
  List<B> bs = []
}

class B {
  List<C> cs = []
}

class C {}
class C1 extends C {}
class C2 extends C {}
class C3 extends C {}

The goal here is to find the first C2 instance, given an instance of A. The pre-Java 8 code looks like the following:

public C2 findFirstC2(A a) {
    for (B b : a.getBs()) {
        for (C c : b.getCs()) {
            if (c instanceof C2) {
                return (C2) c;
            }
        }
    }
    return null;
}

In this code, I made the assumption that the collections are always non-null. The original code I was working on did not make that assumption, and was more complicated as a result. We will revisit the more complicated case later. This code is pretty straightforward: two loops and a conditional, plus an early exit if we find an instance of C2, and return null if we exit the loops without having found anything.

Refactoring to streams using Java 8's stream API is not too bad, though we need to introduce the flat-map concept. Martin Fowler's simple explanation is better than any I would come up with so I will repeat it here: "Map a function over a collection and flatten the result by one-level". In our example, each B has a collection of C. The flat-map operation over a collection of B will basically return a stream of all C for all B. For example, if there are two B instances in the collection, the first having 3 C and the second having 5 C, then the flat-map operation returns a stream of 8 C instances (effectively combining the 3 from the first C and 5 from the second C, and flattening by one level up). With the new flat-map tool in our tool belts, here is the Java 8 code using the stream API:

public Optional<C2> findFirstC2(A a) {
    return a.getBs().stream()
            .flatMap(b -> b.getCs().stream())
            .filter(C2.class::isInstance)
            .map(C2.class::cast)
            .findFirst();
}

In the above code, we first stream over the collection of B. Next is where we apply the flatMap method to get a stream of all C. The one somewhat tricky thing about the Java 8 flatMap method is that the mapper function must return a stream. In our example, we use b.getCs().stream() as the mapper function, thus returning a stream of C. From then on we can apply the filter and map operations, and close out with the findFirst short-circuiting (because it stops at the first C2 it finds) terminal operation which returns an Optional that either contains a value, or is empty.

If you have read any of my previous posts, you won't be surprised that I prefer the functional-style of the Java 8 stream API, for the same reasons I've listed previously (e.g. declarative code, no explicit loops or conditionals, etc.). And as we've seen before in previous posts, we can make the above example generic very easily:

public <T extends C> Optional<T> findFirst(A a, Class<T> clazz) {
    return a.getBs().stream()
            .flatMap(b -> b.getCs().stream())
            .filter(clazz::isInstance)
            .map(clazz::cast)
            .findFirst();
}

Of course, it is also not difficult to make the imperative version with loops generic, using the isAssignableFrom and cast methods in the Class class. And you can even make it just as short by removing the braces, as in the following:

public <T> T findFirstC2(A a, Class<T> clazz) {
    for (B b : a.getBs())
        for (C c : b.getCs())
            if (clazz.isAssignableFrom(c.getClass()))
                return clazz.cast(c);
    return null;
}

I never omit the braces even for one liners, because I believe it is a great way to introduce bugs (remember goto fail a few years ago?). Braces or no braces, why prefer the more functional style to the imperative style? Some is obviously personal preference, and what you are used to. Clearly if you are used to and comfortable with reading imperative code, it won't be an issue to read the above code. But the same goes for functional style, i.e. once you learn the basic concepts (map, filter, reduce, flat-map, etc.) it becomes very easy to quickly see what code is doing (and what is intended).

One other thing is that instead of using stream(), you can easily switch to parallelStream() which then automatically parallelizes the code. But simply using parallelStream() will not always (counter-intuitively) make code faster, e.g. for small collections it will probably make it slower due to context switching. But if things like transformation or filtering take a significant amount of time, then parallelizing the code can produce significant performance improvement. Unfortunately there are no hard rules though, and whether parallelizing speeds the code up depends on various and sundry factors.

The examples above were very simple. The original code was more complex because it did not make any assumptions about nullability of the original argument or the nested collections. Here is the code:

public C2 findFirstC2(A a) {
    if (a == null || a.getBs() == null) {
        return null;
    }

    for (B b : a.getBs()) {
        List<C> cs = b.getCs();
        if (cs == null) {
            continue;
        }

        for (C c : cs) {
            if (c instanceof C2) {
                return (C2) c;
            }
        }
    }
    return null;
}

This code is more difficult to read than the original code due to the additional null-checking conditionals. There are two loops, three conditionals, a loop continuation, and a short-circuit return form within a nested loop. So what does this look like using the Java 8 stream API? Here is one solution:

public Optional<C2> findFirstC2(A a) {
    return Optional.ofNullable(a)
            .map(A::getBs)
            .orElseGet(Lists::newArrayList)
            .stream()
            .flatMap(this::toStreamOfC)
            .filter(C2.class::isInstance)
            .map(C2.class::cast)
            .findFirst();
}

private Stream<? extends C> toStreamOfC(B b) {
    return Optional.ofNullable(b.getCs())
            .orElseGet(Lists::newArrayList)
            .stream();
}

That looks like a lot, so let's see what is going on. The main difference is that we need to account for possible null values. For that the code uses the Optional#ofNullable method which unsurprisingly returns an Optional. We are also using map operations on the Optional objects, which returns an empty Optional if it was originally empty, otherwise it applies the operation. We are also using the Optional#orElseGet method to ensure we are always operating on non-null collections, for example if a.getBs() returns null then the first orElseGet provides a new ArrayList. In this manner, the code always works the same way whether the intermediate collections are null or not. Instead of embedding a somewhat complicated map operation in the flatMap I extracted the toStreamOfC method, and then used a method reference. When writing code in functional style, often it helps to extract helper methods, even if that ends up creating more code because, in the end, the code is more easily understood.

The code in this more complex example illustrates the declarative nature of the functional style. Once you are familiar with the functional primitives (like map, flat-map, filter, and so on) reading this code is quite easy and fast, because it reads like a specification of the problem. Like reading code, writing code in the functional style takes some practice and getting used to, but once you get the hang of it, I think you will find you can often write the code faster. The main difference when writing code in functional style is that I do more thinking about what exactly I am trying to do before just slinging code. Until next time, auf Wiedersehen.

This blog was originally published on the Fortitude Technologies blog here.

Towards More Functional Java using Generators and Filters

Posted on October 12, 2016 by Scott Leberknight

Last time we saw how to use lambdas as predicates, and specifically how to use them with the Java 8 Collection#removeIf method in order to remove elements from a map based on the predicate. In this article we will use a predicate to filter elements from a stream, and combine it with a generator to find the first open port in a specific range. The use case is a (micro)service-based environment where each new service binds to the first open port it finds in a specific port range. For example, suppose we need to limit the port range of each service to the dynamic and/or private ports (49152 to 65535, as defined by IANA). Basically we want to choose a port at random in the dynamic port range and bind to that port if it is open, otherwise repeat the process until we find an open port or we have tried more than a pre-defined number of times.

The original pre-Java 8 code to accomplish this looked like the following:

public Integer findFreePort() {
    int assignedPort = -1;
    int count = 1;
    while (count <= MAX_PORT_CHECK_ATTEMPTS) {
        int checkPort = MIN_PORT + random.nextInt(PORTS_IN_RANGE);
        if (portChecker.isAvailable(checkPort)) {
            assignedPort = checkPort;
            break;
        }
        count++;
    }
    return assignedPort == -1 ? null : assignedPort;
}

There are a few things to note here. First, the method returns an Integer to indicate that it could not find an open port (as opposed to throwing an exception, which might or might not be better). Second, there are two mutable variables assignedPort and count, which are used to store the open port (if found) and to monitor the number of attempts made, respectively. Third, the while loop executes so long as as the maximum number of attempts has not been exceeded. Fourth, a conditional inside the loop uses a port checker object to determine port availability, breaking out of the loop if an open port is found. Finally, a ternary expression is used to check the assignedPort variable and return either null or the open port.

Taking a step back, all this code really does is loop until an open port is found, or until the maximum attempts has been exceeded. It then returns null (if no open port was found) or the open port as an Integer. There are two mutable variables, a loop, a conditional inside the loop with an early break, and another conditional (via the ternary) to determine the return value. I'm sure there are a few ways this code could be improved without using Java 8 streams. For example, we could simply return the open port from the conditional inside the loop and return null if we exit the loop without finding an open port, thereby eliminating the assignedPort variable. Even so it still contains a loop with a conditional and an early exit condition. And some people really dislike early returns and only want to see one return statement at the end of a method (I don't generally have a problem with early exits from methods, so long as the method is relatively short). Not to mention returning null when a port is not found forces a null check on callers; if a developer isn't paying attention or this isn't documented, perhaps they omit the null check causing a NullPointerException somewhere downstream.

Refactoring this to use the Java 8 stream API can be done relatively simply. In order to accomplish this we want to do the following, starting with generating a sequence of random ports. For each randomly generated port, filter on open ports and return the first open port we find. If no open ports are found after limiting our attempts to a pre-determined maximum, we want to return something that clearly indicates no open port was found, i.e. that the open port is empty. I chose the terminology here very specifically, to correspond to both general functional programming concepts as well as to the Java 8 API methods we can use.

Here is the code using the Java 8 APIs:

public OptionalInt findFreePort() {
    IntSupplier randomPorts = () -> MIN_PORT + random.nextInt(PORTS_IN_RANGE);
    return IntStream.generate(randomPorts)
            .limit(MAX_PORT_CHECK_ATTEMPTS)
            .filter(portChecker::isAvailable)
            .findFirst();
}

Without any explanation you can probably read the above code and tell generally what it does, because we are declaring what should happen, as opposed to listing the explicit instructions for how to do it. But let's dive in and look at the specifics anyway. The refactored method returns an OptionalInt to indicate the presence or absence of a value; OptionalInt is just the version of the Optional class specialized for primitive integers. This better matches the semantics we'd like, which is to clearly indicate to a caller that there may or may not be a value present. Next, we are using the generate method to create an infinite sequence of random values, using the specified IntSupplier (which is a specialization of Supplier for primitive integers). Suppliers do exactly what they say they do - supply a value, and in this case a random integer in a specific range. Note the supplier is defined using a lambda expression.

The infinite sequence is truncated (limited) using the limit method, which turns it into a finite sequence. The final two pieces are the filter and findFirst methods. The filter method uses a method reference to the isAvailable method on the portChecker object, which is just a shortcut for a lambda expression when the method accepts a single value that is the lambda argument. Finally, we use findFirst which is described by the Javadocs as a "short-circuiting terminal operation" which simply means it terminates a stream, and that as soon as its condition is met, it "short circuits" and terminates. The short-circuiting behavior is basically the same as the break statement in the original pre-Java 8 code.

So now we have a more functional version that finds free ports with no mutable variables and a more semantically correct return type. As we've seen in several of the previous articles in this ad-hoc series, we are seeing common patterns (i.e. map, filter, collect/reduce) recurring in a slightly different form. Instead of a map operation to transform an existing stream, we are generating a stream from scratch, limiting to a finite number of attempts, filtering the items we want to accept, and then using a short-circuiting terminal operation to return the value found, or an empty value as an OptionalInt.

As you can probably tell, I am biased toward the functional version for various reasons such as the declarative nature of the code, no explicit looping or variable mutation, and so on. In this case I think the more functional version is much more readable (though I am 100% sure there will be people who vehemently disagree, and that's OK). In addition, because we are using what are effectively building blocks (generators, map, filter, reduce/collect, etc.) we can much more easily make something generic to find the first thing that satisifies a filtering condition given a supplier and limit. For example:

public <T> Optional<T> findFirst(long maxAttempts,
                                 Supplier<T> generator,
                                 Predicate<T> condition) {
    return Stream.generate(generator)
            .limit(maxAttempts)
            .filter(condition)
            .findFirst();
}

Now we have a re-usable method that can accept any generator and any predicate. For example, suppose you want to find the first random number over two billion if it occurs within 10 attempts, or else default to 42 (naturally). Assuming you have a random number generator object rand, then you could call the findFirst method like this, making use of the orElse method on Optional to provide a default value:

Integer value = findFirst(10, rand::nextInt, value -> value > 2_000_000_000).orElse(42);

So as I mentioned in the last article on predicates, there is a separation of concerns achieved by using the functional style that simply is not possible using traditional control structures such as the while loop and explicit if conditional as in the first example of this article. (*) Essentially, the functional style is composable using basic building blocks, which is another huge win. Because of this composability, in general you tend to write less code, and the code that you do write tends to be more focused on the business logic you are actually trying to perform. And when you do see the same pattern repeated several times, it is much easier to extract the commonality using the functional style building blocks as we did to create the generic findFirst method in the last example. To paraphrase Yoda, once you start down the path to the functional side, forever will it dominate your destiny. Unlike the dark side of the Force, however, the functional side is much better and nicer. Until next time, arrivederci.

You can find all the sample code used in this blog and the others in this series on my GitHub in the java8-blog-code repository.

(*) Yes, you can simulate functional programming using anonymous inner classes prior to Java 8, or you can use a library like Guava and use its functional programming idioms. In general this tends to be verbose and you end up with more complicated and awkward-looking code. As the Guava team explains:

Excessive use of Guava's functional programming idioms can lead to verbose, confusing, unreadable, and inefficient code. These are by far the most easily (and most commonly) abused parts of Guava, and when you go to preposterous lengths to make your code "a one-liner," the Guava team weeps.

This blog was originally published on the Fortitude Technologies blog here.