Java 8 Friday: Let’s Deprecate Those Legacy Libs

At Data Geekery, we love Java. And as we’re really into jOOQ’s fluent API and query DSL, we’re absolutely thrilled about what Java 8 will bring to our ecosystem.

Java 8 Friday

Every Friday, we’re showing you a couple of nice new tutorial-style Java 8 features, which take advantage of lambda expressions, extension methods, and other great stuff. You’ll find the source code on GitHub. For the last two Fridays, we’ve been off for our Easter break, but now we’re back with another fun article:

Let’s Deprecate Those Legacy Libs

d8938bef47ea2f62ed0543dd9e35a483Apart from Lambdas and extension methods, the JDK has also been enhanced with a lot of new library code, e.g. the Streams API and much more. This means that we can critically review our stacks and – to the great joy of Doctor Deprecator – throw out all the garbage that we no longer need. Here are a couple of them, just to name a few:

LINQ-style libraries

There are lots of libraries that try to emulate LINQ (i.e. the LINQ-to-Collections part). We’ve already made our point before, because we now have the awesome Java 8 Streams API. 5 years from today, no Java developer will be missing LINQ any longer, and we’ll all be Streams-masters with Oracle Certified Streams Developer certifications hanging up our walls. Don’t get me wrong. This isn’t about LINQ or Streams being better. They’re pretty much the same. But since we now have Streams in the JDK, why worry about LINQ? Besides, the SQLesque syntax for collection querying was misleading anyway. SQL itself is much more than Streams will ever be (or needs to be). So let’s list a couple of LINQesque APIs, which we’ll no longer need: LambdaJ This was a fun attempt at emulating closures in Java through arcane and nasty tricks like ThreadLocal. Consider the following code snippet (taken from here):

// This lets you "close over" the
// System.out.println method
Closure println = closure(); { 
  of(System.out).println(var(String.class));
}

// in order to use it like so:
println.apply("one");
println.each("one", "two", "three");

Nice idea, although that semi-colon after closure(); and before that pseudo-closure-implementation block, which is not really a closure body… all of that seems quite quirky ;-) Now, we’ll write:

Consumer<String> println = System.out::println;

println.accept("one");
Stream.of("one", "two", "three").forEach(println);

No magic here, just plain Java 8. Let’s hear it one last time for Mario Fusco and Lambdaj. Linq4j Apparently, this is still being developed actively… Why? Do note that the roadmap also has a LINQ-to-SQL implementation in it, including:
Parser support. Either modify a Java parser (e.g. OpenJDK), or write a pre-processor. Generate Java code that includes expression trees.
Yes, we’d like to have such a parser for jOOQ as well. It would allow us to truly embed SQL in Java, similar to SQLJ, but typesafe. But if we have the Streams API, why not implement something like Streams-to-SQL? We cannot say farewell to Julian Hyde‘s Linq4j just yet, as he’s still continuing work. But we believe that he’s investing in the wrong corner. Coolection This is a library with a fun name, and it allows for doing things like…

from(animals).where("name", eq("Lion"))
             .and("age", eq(2))
             .all();

from(animals).where("name", eq("Dog"))
             .or("age", eq(5))
             .all();

But why do it this way, when you can write:

animals.stream()
       .filter(a -> a.name.equals("Lion")
                 && a.age == 2)
       .collect(toList());

animals.stream()
       .filter(a -> a.name.equals("Dog")
                 || a.age == 5)
       .collect(toList());

Let’s hear it for Wagner Andrade. And then off to the bin

Half of Guava

Guava has been pretty much a dump for all sorts of logic that should have been in the JDK in the first place. Take com.google.guava.base.Joiner for instance. It is used for string-joining:

Joiner joiner = Joiner.on("; ").skipNulls();
. . .
return joiner.join("Harry", null, "Ron", "Hermione");

No need, any more. We can now write:

Stream.of("Harry", null, "Ron", "Hermione")
      .filter(s -> s != null)
      .collect(joining("; "));

Note also that the skipNulls flag and all sorts of other nice-to-have utilities are no longer necessary as the Streams API along with lambda expressions allows you to decouple the joining task from the filtering task very nicely. Convinced? No? What about: And then, there’s the whole set of Functional stuff that can be thrown to the bin as well: https://code.google.com/p/guava-libraries/wiki/FunctionalExplained Of course, once you’ve settled on using Guava throughout your application, you won’t remove its usage quickly. But on the other hand, let’s hope that parts of Guava will be deprecated soon, in favour of an integration with Java 8.

JodaTime

Now, this one is a no-brainer, as the popular JodaTime library got standardised into the java.time packages. This is great news. Let’s hear it for “Joda” Stephen Colebourne and his great work for the JSR-310.

Apache commons-io

The java.nio packages got even better with new methods that nicely integrate with the Streams API (or not). One of the main reasons why anyone would have ever used Apache Commons IO was the fact that it is horribly tedious to read files prior to Java 7 / 8. I mean, who would’ve enjoyed this piece of code (from here):

try (RandomAccessFile file = 
     new RandomAccessFile(filePath, "r")) {
    byte[] bytes = new byte[size];
    file.read(bytes);
    return new String(bytes); // encoding?? ouch!
}

Over this one?

List<String> lines = FileUtils.readLines(file);

But forget the latter. You can now use the new methods in java.nio.file.Files, e.g.

List<String> lines = Files.readAllLines(path);

No need for third-party libraries any longer!

Serialisation

Throw it all out, for there is JEP 154 deprecating serialisation. Well, it wasn’t accepted, but we could’ve surely removed about 10% of our legacy codebase.

A variety of concurrency APIs and helpers

With JEP 155, there had been a variety of improvements to concurrent APIs, e.g. to ConcurrentHashMaps (we’ve blogged about it before), but also the awesome LongAdders, about which you can read a nice article over at the Takipi blog. Haven’t I seen a whole com.google.common.util.concurrent package over at Guava, recently? Probably not needed anymore.

JEP 154 (Serialisation) wasn’t real

It was an April Fools’ joke, of course…

Base64 encoders

How could this take so long?? In 2003, we’ve had RFC 3548, specifying Base16, Base32, and Base64 data encodings, which was in fact based upon base 64 encoding specified in RFC 1521, from 1993, or RFC 2045 from 1996, and if we’re willing to dig further into the past, I’m sure we’ll find earlier references to this simple idea of encoding binary data in text form. Now, in 2014, we finally have JEP 135 as a part of the JavaSE8, and thus (you wouldn’t believe it): java.util.Base64. Off to the trash can with all of these libraries! … gee, it seems like everyone and their dog worked around this limitation, prior to the JDK 8…

More?

Provide your suggestions in the comments! We’re curious to hear your thoughts (with examples!)

Conclusion

As any Java major release, there is a lot of new stuff that we have to learn, and that allows us to remove third-party libraries. This is great, because many good concepts have been consolidated into the JDK, available on every JVM without external dependencies. Disclaimer: Not everything in this article was meant seriously. Many people have created great pieces of work in the past. They have been very useful, even if they are somewhat deprecated now. Keep innovating, guys! :-) Want to delve more into the many new things Java 8 offers? Go have a look over at the Baeldung blog, where this excellent list of Java 8 resources is featured:
Java 8
… and stay tuned for our next Java 8 Friday blog post, next week!

18 thoughts on “Java 8 Friday: Let’s Deprecate Those Legacy Libs

  1. Not sure why, but the author at the end just forgot to add: “and finally forget java, start using Scala which already has those features and even more. And you do not need to hack language to make it functional.

  2. Op4j falls in the same category too. There are still many jdk 1.6/1.7 systems running, especially within large organizations. Until they do the 1.8 switch, they can still take advantage of some features brought by these libs. Some will continue to innovate or develop some extra features. Hibernate annotations offers more features than JPA. The small projects move faster, so we should still keep an eye on them.

    1. Op4j falls in the same category too

      Great suggestion. How could we miss it!? There had been a previous post about Op4j. Clearly, we can say thanks and goodbye to this great library, now.

      Hibernate annotations offers more features than JPA.

      Yes, I guess that in this area, standardisation will always be much behind the individual innovators – much like the SQL standard, which is far behind the implementations in many cases.

  3. You’re mistaken about the syntax introduced by libraries such as Coollection. The whole point of something like:

    from(animals).where(“name”, eq(“Lion”)).and(“age”, eq(2))

    instead of

    animals.stream().filter(a -> a.name.equals(“Lion”) && a.age == 2)

    is that the “eq” is NOT evaluated before it enters where/filter, it could build an expression tree like in LINQ and allows transformation into workflow rules, SQL, XQuery, property binding in JavaFX, or dynamically rewritten and compiled/run at runtime.

    That’s much more useful than Java 8’s cheap implementation of lambda which is no more than a shortcut to anonymous class plus a tiny (stream) API offering nothing that others haven’t done.

    1. I’m not quite sure what you mean. In Java 8, the equals and == expressions aren’t evaluated until the actual stream element is being filtered…

  4. The important thing with string joining is to prevent delimiter collision bugs. The programmer must take care to supply strings that are escaped, or quoted, or cannot or do not contain the delimiter; and do not consist of no strings or just one empty string. The join or joining method could be deprecated in favour of a safe joiner that produces a different class that represents a potentially unsplittable joined string or stream. The program will not compile without an extra method call to convert to an ordinary splittable joined string or stream, with a name that explains what was done to guarantee that the result is in fact splittable.

    1. Delimiters aren’t even the only thing you have to worry about if you’re using join. e.g., if you’re going to show the string to the user, you also have to worry about whether the delimiters you’re using are appropriate for their locale, whether you have to wrap the elements of the string with directional isolate characters (delimiters tend to have weak direction and you don’t want elements suddenly switching places!), and all kinds of horrid stuff.

      I had a similar solution in mind to what you propose. Introduce a UserVisibleString class to house a string which the user is allowed to see, and MoreCollectors.joiningUserVisibleStrings would take a Stream, take a UserVisibleString for the delimiter (to force you to look that up from a resource bundle) and return UserVisibleString.

  5. People will be keen to use the new Base64 encoder in new code. But I hope old ones are not going in the bin without some very careful retesting.

    A few projects ago I thought it would be a good idea to get rid of the warnings about using a proprietary sun encoder by replacing it with an apache encoder. But it is not that simple: there are padding, line length and character set variations to configure and test. I ended up just refactoring each distinct encode or decode call idiom into one wrapper method to reduce the total number of warnings. For good measure I inserted a TODO comment in the wrapper to mention some of the test cases that would be needed if we were ever actually forced to change the encode/decode method.

  6. You mention Guava but what about stuff that’s contain/used from commons-collections like functions, closures, etc.?

Leave a Reply