Keeping Pace With What’s New in Java 14
These are comments to this video.
Note: Original video also talks about Sealed classes and interfaces
(preview language feature)
in Java 15 to be released in September 2020. You can read about this here https://www.infoq.com/articles/java-sealed-classes/
Records (preview language feature)
Based on https://dzone.com/articles/a-first-look-at-records-in-java-14
UPDATE
After publishing original post, I’ve read original JEP for records and I was astonished to find the following:
While it is superficially tempting to treat records as primarily being about boilerplate reduction, we instead choose a more semantic goal: modeling data as data…Records go well with sealed types (JEP 360); records and sealed types taken together form a construct often referred to as algebraic data types. Further, records lend themselves naturally to pattern matching. Because records couple their API to their state description, we will eventually be able to derive deconstruction patterns for records as well, and use sealed type information to determine exhaustiveness in
switch
expressions with type patterns or deconstruction patterns.
https://openjdk.java.net/jeps/359
So, Java’s records are essentially product types. It is not just about reducing boilerplate. Practically, records are needed for pattern matching that is designed to be added in future version of Java. I will write separate post about this later.
In the video there is answered question. Why records doesn’t follows JavaBean naming convention?
…Like an
enum
, arecord
is a restricted form of class. It declares its representation, and commits to an API that matches that representation… A central aspect of Java’s philosophy is that names matter… That is, aPerson
class with propertiesfirstName
andlastName
is clearer and safer than an anonymous tuple ofString
andString
.
https://openjdk.java.net/jeps/359
END OF UPDATE
This is similar to data class in Kotlin. This is special kind of class that is intended to hold pure data in it. Typical use-cases are: DTO — data transfer object or domain model class.
Code example:
Note, there is mistake. Records doesn’t implements java.io.Serialzable
by default. I think, this is bug in IntelliJ IDEA.
Actually, it is demonstrated later in the video.
You can see in line 5 in the link provided above of the decompiled class there is no mentioning of java.io.Serializable
.
final class examples.Person extends java.lang.Record
Record class is final.
It extends java.lang.Record
, which is the base class for all records, much like java.lang.Enum
is the base class for all enums. There is a public constructor that is generated for us. For each field there is getter-method to it with exact same name (no “get” prefix!). Three other methods are generated: toString()
, hashCode()
and equals()
. They all rely on invokedynamic
to dynamically invoke the appropriate method containing the implicit implementation. See here https://alex-ber.medium.com/explaining-invokedynamic-dynamical-hashcode-implementation-part-v-16eb318fcd47 for more details.
Another code example:
What are old ways to define record?
- Use of some unrated existing class. One popular one is SimpleEntry (because Pair is not present in the JDK). The main disadvantages:
- we’re losing meaningful names , moreover, the names are misleading —
getKey()
andgetValue()
and not,say,getFirstName()
,getLastName()
. - We are using the same type for different DTO/Model class, so compiler can’t help us to distinguish the use cases and we don’t have semantic information in what this partial DTO/Model class holds.
I’ve seen such usage couple of times also.
2. Class with public
fields only.
Actually, from time to time I’m encountering with such solution in different projects. The declaration is short, but it goes with following drawbacks:
- You can’t add field validation. If you have
double amount
, you can’tvalidate precondition on state
thatamount≥0
for example. - If you have some complex state you don’t have place to handle it. Typically, it is done in
setter
-method. The work-around is to add such complexsetter
-method. The drawback is nobody expect that you class has such method, because you state is defined as set ofpublic
fields that are assigned directly. - You can’t make such object
immutable
, you have access to it to read the value, so you can also write to it. - You don’t have readable
toString(),
etc for debugging. If you start to add them, it takes just a little more effort to convert this field to private and to addgetter
-method to it. See next bullet.
3. Full-blown class, may be as JavaBean. Write down whole boilerplate code manually.
3. Full-blown class, using modern IDE to generate most the boilerplate code. This my currently personally preferable way. The main drawbacks are:
- poor readability — you need to read a lot of irrelevant code; I’m mitigating this using naming convention, DTO suffix for the class name, etc.
- difficulty of code modification — If you need to add new field, you should regenerated all
equals()/hashCode()/toString()
methods. If you have some manual change (for example, you’re omitting some field for equality test), you should remember to redo it after automatic code generation. I’m mitigating this by looking on code diff after I’m regenerated the code and careful investigation of such code. In practice, I’ve never deleted such code.
4. Use Project Lombok. Quote: “Project Lombok is a java library that…plugs into your editor and build tools, spicing up your java. Never write another getter or equals method again, with one annotation your class has a fully featured builder.” Lombok uses annotation processing through APT (Annotation Processing Tool), so, when the compiler calls it, the library generates new source files based on annotations in the originals. The main drawback for me is incompatibility with Spring Boot:
The properties that map to
@ConfigurationProperties
classes available in Spring Boot, which are configured via properties files, YAML files, environment variables etc., are public API but the accessors (getters/setters) of the class itself are not meant to be used directly…Some people use Project Lombok to add getters and setters automatically. Make sure that Lombok does not generate any particular constructor for such a type, as it is used automatically by the container to instantiate the object.
It is very difficult to debug Lombok. It took me couple of hours to make @ConfigurationProperties works (it was completely my fault, the problem was in wrong configurations in property files), at the time I just don’t want to spend extra time to configure Lombok (that is not trivial, but shouldn’t be hard) and then if it didn’t work I can’t debug it (I know how to be debug Spring Boot).
Nevertheless, I know a lot of people that happily use Lombok (even with Spring Boot, just they don’t use @ConfigurationProperties at all).
Pattern match for instanceof (preview language feature)
Based on https://www.baeldung.com/java-pattern-matching-instanceof
Old way:
New way:
Quote:
Let’s understand what is happening here. In the first,
if
block, we matchanimal
against the type patternCat cat
. First, we test the animal variable to see if it’s an instance ofCat
. If so, it’ll be cast to ourCat
type, and finally, we assign the result tocat
.It is important to note that the variable name
cat
is not an existing variable, but instead a declaration of a pattern variable.We should also mention that the variables
cat
anddog
are only in scope and assigned when the respective pattern match expressions returntrue
. Consequently, if we try to use either variable in another location, the code will generate compiler errors.
TextBlocks (second preview)
See https://www.baeldung.com/java-text-blocks
https://www.baeldung.com/java-multiline-string
Text blocks just provide us with another way to write String literals in our source code. The result type of a text block is still a String
.
Inside the text blocks, we can freely use newlines and quotes without the need for escaping. It allows us to include literal fragments of HTML, JSON, SQL, or whatever we need, in a more elegant and readable way.
In the resulting String, the (base) indentation and the first newline are not included.
Code example:
This is equivalent to:
Another popular alternatives are:
- To copy multi-line string and paste in inside two double quotes in modern IDEs. Many modern IDEs support multi-line copy/paste. Eclipse and IntelliJ IDEA are examples of such IDEs.
- To store multi-line string in a text file. Use some utility method to read it from file (prior Java 8 I’ve used FileUtils and IOUtils from commons-io package), for example:
The reason for second
preview is addition of two escape sequences.
- Escaping Line Terminators — we can ignore new line.
This is equivalent to:
Note: I’m frequently using this escape sequence in Python.
- Escaping Spaces — we can preserve any spaces spaces in front of new escape sequence \s.
This is equivalent to:
Note: the spaces in the example above are replaced with the ‘·’ symbol to make them visible.
Switch expression (standard feature)
See https://www.techiediaries.com/java/java-14-13-switch-expressions-example/
Note: It is preview feature in Java 12 and Java 13.
Note: In Java 13 there was big breaking change, see http://sandny.com/2019/11/17/java-13-switch-expressions/ so the code will look differently on Java 12.
In enhanced switch expression the entire switch
block “gets a value” that can then be assigned to a variable in same statement.
Let’s consider classic switch example:
Note: The break statements ensures that the next block in the switch statement is not executed.
This code will print out “August”
(in line 4 we’re assigning 8 to month
).
Using a new syntax this can be rewritten as:
Note:
- It uses the
->
operator instead of the colon - We don’t need the
break
statement to stop the execution from flowing to the next cases. - We can assign the switch expressions to variables or place them wherever expressions are expected in your Java code.
Java 14 also introduced a new yield
statement to yield a value which becomes the value of the enclosing switch expression.
For example,
Look on default
clause. It was modified in two ways. No, this is code block, so curly braces are required. In order to “return” value from the default
clause new reserved word “yield”
is used.
A return
statement returns control to the invoker of a method (§8.4, §15.12) or constructor (§8.8, §15.9) while a yield
statement transfers control by causing an enclosing switch
expression to produce a specified value.
Note: In Python yield
is used in generators (this is a subset of more general coroutines concept). yield
is a keyword in Python that is used to return from a function without destroying the states of its local variable and when the function is called, the execution starts from the last yield statement. This has nothing to do with Java’s yield.
For some additional look on:
Foreign Memory Access API in Java 14
https://www.baeldung.com/java-foreign-memory-access
Quote from link above:
Before the introduction of the foreign memory access API in Java, there were two main ways to access native memory in Java. These are java.nio.ByteBuffer and sun.misc.Unsafe [and from Java 9 java.lang.invoke.VarHandle see below] classes.
Note: In the bracket this my addition.
Moreover,
AtomicInteger
is still implemented using Unsafe (that was moved tojdk.internal.misc.Unsafe
). It has interesting comment:
This class intended to be implemented using VarHandles, but there are unresolved cyclic startup dependencies.
AtomicReference
was refactored to use VarHandle
Part of the purpose for
VarHandle
s is to replace operations insun.misc.Unsafe
with a safe equivalent.
2. SequenceLayout
is C-style array
of the same type stored in memory.
3. GroupLayout
is C-style struct
or union
stored in memory.
Guide to the @Serial Annotation in Java 14
https://www.baeldung.com/java-14-serial-annotation
Quote from link above:
Similarly to @Override, this annotation is used in combination with the serial lint flag to perform compile-time checks for the serialization-related members of a class.
A Guide to jpackage in Java 14
https://www.baeldung.com/java14-jpackage
Quote from link above:
jpackage is a command-line tool to create native installers and packages for Java applications.
It’s an incubating feature under the jdk.incubator.jpackage module.
- Helpful NullPointerExceptions in Java 14
https://www.baeldung.com/java-14-nullpointerexception
Quote from link above:
In essence, JEP 358 aims to improve the readability of NullPointerExceptions, generated by JVM, by describing which variable is null.