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)
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
switchexpressions with type patterns or deconstruction patterns.
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?
recordis 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, a
Personclass with properties
lastNameis clearer and safer than an anonymous tuple of
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.
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
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:
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 —
- 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’t
validate precondition on statethat
- 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 complex
setter-method. The drawback is nobody expect that you class has such method, because you state is defined as set of
publicfields 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 add
getter-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
@ConfigurationPropertiesclasses 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)
Let’s understand what is happening here. In the first,
ifblock, we match
animalagainst the type pattern
Cat cat. First, we test the animal variable to see if it’s an instance of
Cat. If so, it’ll be cast to our
Cattype, and finally, we assign the result to
It is important to note that the variable name
catis not an existing variable, but instead a declaration of a pattern variable.
We should also mention that the variables
dogare only in scope and assigned when the respective pattern match expressions return
true. Consequently, if we try to use either variable in another location, the code will generate compiler errors.
TextBlocks (second preview)
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
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.
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)
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
Using a new syntax this can be rewritten as:
- It uses the
->operator instead of the colon
- We don’t need the
breakstatement 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.
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.
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).
yieldis 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
For some additional look on:
Foreign Memory Access API in Java 14
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.
AtomicIntegeris still implemented using Unsafe (that was moved to
jdk.internal.misc.Unsafe). It has interesting comment:
This class intended to be implemented using VarHandles, but there are unresolved cyclic startup dependencies.
Part of the purpose for
VarHandles is to replace operations in
sun.misc.Unsafewith a safe equivalent.
SequenceLayout is C-style
array of the same type stored in memory.
GroupLayout is C-style
union stored in memory.
Guide to the @Serial Annotation in Java 14
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
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
Quote from link above:
In essence, JEP 358 aims to improve the readability of NullPointerExceptions, generated by JVM, by describing which variable is null.