Skip to content

It’s Java 8 Playtime!

Today we are going to look at Java 8′s shininess.

The task at hand is to implement a very simple, standalone HTTP server that would parse the query parameters from a GET request and return a trivial bit of JSON-formatted data.

A Java 8 “hello name” server, in other words.

I am also trying to see how many new toys I can work into the project how idiomatically I can make the solution so that I can get a ‘feel’ for the “New Java.”

Without further ado:

package jdk8;

import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpServer;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) throws IOException {
        InetSocketAddress addr = new InetSocketAddress(8080);
        HttpServer server = HttpServer.create(addr, 0);

        server.createContext("/", (HttpExchange ex) -> {
            if ("GET".equalsIgnoreCase(ex.getRequestMethod())) {
                Headers responseHeaders = ex.getResponseHeaders();
                responseHeaders.set("Content-Type", "application/json");
                ex.sendResponseHeaders(200, 0);

                try (OutputStream responseBody = ex.getResponseBody()) {
                    responseBody.write(generateResponse(extractParams("name", ex.getRequestURI().getQuery())).getBytes());
                } catch (Exception e) {
                    e.printStackTrace(System.err);
                }
            }
        });
        server.setExecutor(Executors.newCachedThreadPool());
        server.start();
        System.out.printf("Server created; listening on port %d\n", addr.getPort());
    }

    private static final String JOIN = " and ";
    private static final String PFX = " ";
    private static final String SFX = "!";
    private static final String NOSTR = PFX + SFX;

    private static String generateResponse(List<String> strings) {
        String s = strings.stream()
                .collect(Collectors.collectingAndThen(Collectors.joining(JOIN, PFX, SFX),
                        (str) -> NOSTR.equals(str) ? str.trim() : str));
        return String.format("{greeting=\"hello%s\"}", s);
    }

    private static List<String> extractParams(String key, String s) {
        // ("" + s): protect against s being null
        return Stream.of(("" + s).split("&"))
                .map(line -> line.split("="))
                .filter(pair -> pair.length == 2)
                .filter(entry -> entry[0].equalsIgnoreCase(key))
                .map(entry -> entry[1])
                .collect(Collectors.toList());
    }
}

There are a fair number of juicy tidbits here, including:

  • The classes in com.sun.net.httpserver. Perfectly legal to use and not contained within one of the restricted APIs, contrary to popular belief. Available since Java 1.6.
  • Try-with-resources. A Java 7 feature, but still little known/used it seems.
  • Executors. An apparently little-known Java 1.5 facility.
  • Lambdas all over the place.
  • Streams and collectors all over the place.

It seems to me that the java.util.stream.Collectors class is worthy of further study. There’s a lot of niceness here, including Collectors.collectingAndThen(), Collectors.joining() and Collectors.toList(). I’m pretty sure that the better I get to know this Class, the less I will end reinventing stuff.

Does all this new and shiny stuff work? Well…the proof, as they say, is in the pudding:

So there you go, a small HTTP server full of Functional Goodness(™). What more can a trendy nerd want?

I guess that IF I was prepared to sacrifice any ‘coolness’ that I may have just accumulated, I would ask something like “But is all that Functional Goodness giving me anything over and above what I would normally get from Java?” And IF I was going to do that, I would be talking about code looking like:

    private static List<String> extractParams(String key, String s) {
        List<String> result = new ArrayList<>();
        // ("" + s): protect against s being null
        for (String param: ("" + s).split("&")) {
            String pair[] = param.split("=");
            if ((pair.length == 2) && key.equalsIgnoreCase(pair[0]))
              result.add(pair[1]);
        }
        return result;
    }

But I don’t want’ to sacrifice all that accrued ‘coolness’, so I certainly won’t put forward the hypothetical question I just hypothetically posed…. In any case, I know all about the potential for parallelism implied by that Functional Goodness, so it would have been silly of me to even think that question, wouldn’t it ;-)

By potential, I mean (of course):

    private static List<String> extractParams(String key, String s) {
        // ("" + s): protect against s being null
        return Stream.of(("" + s).split("&"))
                .parallel()
                .map(line -> line.split("="))
                .filter(pair -> pair.length == 2)
                .filter(entry -> entry[0].equalsIgnoreCase(key))
                .map(entry -> entry[1])
                .collect(Collectors.toList());
    }

I’ve not really seen an example like this “out there”, so I hope that the world is now a better place for having this code snippet in it!

Tags: , ,

C, Java Enterprise Edition, JEE, J2EE, JBoss, Application Server, Glassfish, JavaServer Pages, JSP, Tag Libraries, Servlets, Enterprise Java Beans, EJB, Java Messaging Service JMS, BEA Weblogic, JBoss, Application Servers, Spring Framework, Groovy, Grails, Griffon, GPars, GAnt, Spock, Gradle, Seam, Open Source, Service Oriented Architectures, SOA, Java 2 Standard Edition, J2SE, Eclipse, Intellij, Oracle Service Bus, OSB