Java 9: The Good, The Bad, and Private Interface Methods
Java 9 was released a few weeks ago. Check the release notes, they include many interesting features. However, I think that not everything is as good as Oracle and Java adepts seem to picture it. I see three trends in the Java world, which are good, bad, and ugly, respectively. Let’s start with the good one.
The Platform
The first trend is an obvious improvement of the platform that compiles Java, packages JARs, and runs the bytecode. It definitely becomes better with every new Java release. Here is a list of improvements Java 9 made, which are very useful, without doubt:
- JSR 376: Module System a.k.a. Jigsaw
- JEP 222:
jshell
- JEP 238: Multi-release JARs
- JEP 282:
jlink
- JEP 158: Unified logging
The platform is obviously becoming more mature. This is a good trend.
The JDK
The second trend, which I’ve observed since Java 6, shows that the JDK, which is essentially a collection of classes and interfaces designed, developed, and maintained by Oracle, gets bigger with every new release. In Java 9 they added and extended, besides others, the following:
- JEP 221, 224 225, 261: Javadoc processing (extended)
- JEP 268: XML Catalogs (new)
- JEP 262: TIFF image I/O (new)
- JEP 251: multi-resolution images (new)
- JEP 110: HTTP 2.0 client (new)
- JEP 236: Parser for Nashorn (extended)
Of course some features must be implemented in the JDK itself, like Unicode support (JEP 267), platform-specific Desktop features (JEP 272), Spin-Wait Hints (JEP 285), compact strings (JEP 254), and the process API (JEP 102). Their implementation depends on the underlying platform and has to be provided together with the JVM.
But what is HTTP 2.0 client doing in the JDK, together with JAX-RS, JPA, JAX-WS, JDBC, and many other things that, in my opinion, should stay as far away from Oracle as possible? They are not platform specific and they can be, in a much better way, designed by the open source community as independent packages. Aggregating them under one monster umbrella brand is a mistake, I believe.
I think that big corporations are only killing the software market, instead of making it better, because of the financial and political motives they expose it to. That’s exactly what is happening with JDK. Thanks to the Oracle monopoly it lacks flexibility and dynamicity in growth. In other words, we’re stuck with what Oracle and its big friends think is right.
Thus, making JDK bigger is a bad trend. Instead, I believe, Oracle would only benefit from making it smaller, delegating everything that is not platform-specific to the open source community, supporting programmers somehow and promoting open and effective standardization processes on the market.
The Language
Java was developed by James Gosling in Sun Microsystems in 1995 as an object-oriented language. There were many concerns about this claim of object-orientation and I’m also not sure that Java is more OO than it is procedural. However it is officially object-oriented.
There were many procedural features inherited by Java from C/C++, since its first version, including static methods, NULL, implementation inheritance, etc. It was not a perfect object-oriented language and it was not going to be one, as I understand it. The key idea was to create something that could be written once and ran anywhere. However the language was a big deal also, not just the JVM. It was simple and sexy.
Java 5 made a serious step forward in 2004 and improved the language by adding generics, for-each loop, varargs, and static import. However, annotations and enumerations were introduced, which helped the language to divert from the object paradigm to something completely different and procedural.
Java 7 added try-with-resource in 2011, which was a good move, in line with the OOP paradigm.
Java 8 added lambda expressions in 2014, which was a great feature, but absolutely irrelevant to OOP. Lambda and Streams API turned Java into a mix of the object, procedural, and functional paradigms. Default methods were also added to interfaces, which turned types into libraries of code. Types into libraries! It’s even worse than implementation inheritance, if you ask me.
Now Java 9 made the next “improvement” to interfaces, allowing them to have private methods. Private static methods in types! Can you believe it? What will be the next step? Attributes, in Java 10, I guess.
Also, let’s take a look at what was done to some core classes in the JDK, to understand where the language is heading. Just two examples.
Factory methods for collections (JEP 269). Instead of introducing new constructors and allowing us to do this:
1 | List<Integer> list = new ArrayList<>( 1 , 2 , 3 ); |
…in Java 9 they created more static methods and made us do this:
1 | List<Integer> list = List.of( 1 , 2 , 3 ); |
“Fewer constructors, more static methods!” seems to be the philosophy of those who introduced this JEP. Needless to say that this is completely against the very spirit of object-oriented programming. Objects must be created by constructors, not static methods, no matter what Joshua Bloch says. Static methods make the moment of operator new
usage invisible for us and that’s why the code is way less maintainable—we simply don’t know exactly what class is instantiated and what the real arguments of its ctor are.
By the way, with Cactoos you can do it the right way:
1 | List<Integer> list = new ListOf( 1 , 2 , 3 ); |
This is OOP.
New methods in InputStream
. Three new methods were added to the already over bloated class InputStream
: transferTo()
, readNBytes()
, and readAllBytes()
. Now we are supposed to do this, when we want input stream to copy to an output stream:
1 | input.transferTo(output); |
It’s one of the most typical mistakes young OOP programmers are making: they make their interfaces big. Just because they need more functionality. I guess the interface segregation principle is part of the famous SOLID and is many years old. What’s wrong with you, Oracle? What will the next step be? In Java 10 we will also have saveToFile()
and printToConsole()
? How about emailToAFriend()
?
This is how you would do the same with the IOUtils
utility class from commons-io:
1 | IOUtils.copy(input, output); |
It’s not perfect, but it’s better. The most object-oriented way is to use objects, not utility classes and static methods. This is how it works in Cactoos:
1 | new LengthOf( new TeeInput(input, output)).length(); |
This is OOP.
In my opinion, Java is getting uglier, and this is a trend. Does it mean that it’s time to quit? No! No matter how ugly you are, we will always love you Java!
You may also find these related posts interesting: Each Private Static Method Is a Candidate for a New Class; Flexibility Equates to Lower Quality; Why InputStream Design Is Wrong; Inheritance Is a Procedural Technique for Code Reuse; Temporal Coupling Between Method Calls;
Published on Java Code Geeks with permission by Yegor Bugayenko, partner at our JCG program. See the original article here: Java 9: The Good, The Bad, and Private Interface Methods Opinions expressed by Java Code Geeks contributors are their own. |
“Objects must be created by constructors”
Why? Using static factory methods gives you many benefits:
1) You can use meaningful names.
2) You can an instance of a derived class, if appropriate.
3) You can easily implement some kind of caching mechanism in case when you’re returning immutable objects.
IMHO statement that object MUST be created by constructor is very opinionated.