Java 17 for the Impatient
Learn the basics of Java 17.
Join the DZone community and get the full member experience.
Join For FreeI have been working on Java 8 for a long time and, now, Java 17 has been released, so let's have a quick look at this article which focuses on the latest Java 17 LTS features.
There are lots of features and improvements that have been introduced, however, in this article, we will focus on a limited set:
- Record classes
- Sealed Class
- Switch case
- Enhanced instanceOf Operator
- Compact Number Format
- Text Blocks
- Stream toList
Records Classes
Records classes are immutable and used as data transfer objects with zero boilerplate code. Record classes are defined with the record keyword. It always extends the java.lang.Record
class.
record Country(String name,String capital){}
The above line of code generates functionality automatically like
- All fields are
private
andfinal.
- A canonical constructor for all fields.
- Public accessor for all fields.
equals
,hashcode
, andtoString
methods.
Also, it can be defined locally either inside a class or method.
public class SampleRecordClass {
record Country(String name,String capital){}
public static void main(String[] args) {
Country firstCountry = new Country("Netherlands","Amsterdam");
Country secondCountry = new Country("Germany","Berlin");
System.out.println("First country object is " + firstCountry);
System.out.println("Second country object is " + secondCountry);
System.out.println("Check if both objects equal" + firstCountry.equals(secondCountry));
// Copying object using attribute method of existing records object
Country countryClone = new Country(firstCountry.name,firstCountry.capital);
System.out.println("country clone object" + countryClone);
}
}
Sealed Class
A sealed class specifically lists the permitted direct subclasses. It won’t allow any other class to extend.
public sealed class SampleSealedClassApp permits SampleSealedApp{
}
Though the permits keywords can be removed if all the classes are defined in the same file.
public sealed class SampleSealedClassApp {
final class SampleClass extends SampleSealedClassApp{}
final class SampleSecondClass extends SampleSealedClassApp{}
}
Switch Case
The switch statement in Java has evolved over time. At first, it allowed only primitives then it introduced String. In Java 17, we have the pattern matching of instanceOf with a switch case, which allows us to pass different types of complex objects.
The switch statement can now be written like this
public static void onShow(Country country) {
switch (country) {
case NETHERLANDS, POLAND, GERMANY -> System.out.println("European Country");
case INDIA, BHUTAN, NEPAL -> System.out.println("Asian Country");
default -> System.out.println("It's from Wakanda");
}
}
Switch Statement With Yield
Another way to write switch cases is with blocks where we can add logic inside the block:
public static void onShowWithYield(Country country) {
String output = switch (country) {
case NETHERLANDS, POLAND, GERMANY -> {
System.out.println("European Country" + country);
yield "Country belongs to Europe Continent";
}
case INDIA, BHUTAN, NEPAL -> {
System.out.println("Asian Country" + country);
yield "Country belongs to Asian Continent";
}
default -> "It's from Wakanda";
};
System.out.println(output);
}
Switch Statement With the Return
Also, the switch statement can now return a value, written like this:
public static void onShowWithReturnValue(Country country) {
String output = switch (country) {
case NETHERLANDS, POLAND, GERMANY -> "European Country";
case INDIA, BHUTAN, NEPAL -> "Asian Country";
default -> "It's from Wakanda";
};
System.out.println(output);
}
Switch Statement With Type Coverage
In Java 17, we can also check for the type of selectors as sealed class as we have seen above. It does not need a default case because it does the type coverage with all permitted classes.
sealed interface SampleSealed permits ClassOne, ClassTwo, ClassThree {
}
final class ClassOne implements SampleSealed {
}
final class ClassTwo implements SampleSealed {
}
record ClassThree(String name) implements SampleSealed {
}
static String withSealedClass(SampleSealed sampleSealedClassApp) {
return switch (sampleSealedClassApp) {
case ClassOne classOne -> "Sample class one";
case ClassTwo classTwo -> "Sample class two";
case ClassThree classThree -> "Sample class three";
};
}
In case it does not cover all the possible values, then the compiler will throw an error. As we can see in the example below, the ClassOne
type is missing, so it will generate a compile-time error.
static String withSealedClass(SampleSealed sampleSealedClassApp) {
return switch (sampleSealedClassApp) { //error - Switch statement doesn't cover all possible value
case ClassTwo classTwo -> "Sample class two";
case ClassThree classThree -> "Sample class three";
};
Enhanced instanceOf Operator
An enhanced instanceOf operator allows you to pattern match and eliminates the extra line of code that was required earlier to perform casts:
private static void patternMatchingInstanceOf() {
Object o = new CountryData("Netherlands","Amsterdam","Europe");
if (o instanceof CountryData countryData) {
System.out.println("This capital of Netherlands is " + countryData.capital());
}
}
In the above snippet, the scope of the variable countryData
is specific to the if block. The variable in scope can be used to match the pattern strictly like this:
private static void patternMatchingInstanceOfScope() {
Object o = new CountryData("Netherlands","Amsterdam","Europe");
if (o instanceof CountryData countryData && countryData.continent().equals("Europe")) {
System.out.println("This continent of Netherlands is " + countryData.continent());
}
}
It is important to keep in my mind that the variable inside the scope should not be ambiguous. The condition && above can only be executed successfully after checking the result of instanceOf
the results as true
. If we change the &&
to ||
, the code will not compile.
Compact Number Format
The CompactNumberFormat class is a subclass of NumberFormat class in the java.text
package. It is responsible for formatting a number in compact form. A factory method is added to NumberFormat to format numbers in compact, human-readable form. There are two styles of formats, LONG and SHORT, as shown below
NumberFormat numberFormatLong = NumberFormat
.getCompactNumberInstance(Locale.forLanguageTag("NL"), NumberFormat.Style.LONG);
System.out.println(numberFormatLong.format(2000));
System.out.println(numberFormatLong.format(20000));
System.out.println(numberFormatLong.format(200000));
The output of the above code will look like this:
2 duizend
20 duizend
200 duizend
NumberFormat numberFormatShort = NumberFormat
.getCompactNumberInstance(Locale.forLanguageTag("NL"), NumberFormat.Style.SHORT);
System.out.println(numberFormatShort.format(2000));
System.out.println(numberFormatShort.format(20000));
System.out.println(numberFormatShort.format(200000));
The output of the above code will look like this:
2K
20K
200K
Text Blocks
Text Blocks are used to make code more readable. It allows us to write multi-line strings. A Text Block is started with three quotes followed by the line break and closed by three quotes as shown below:
public static void main(String[] args) {
String multiLineText = """
There are good ships and wood ships,
ships that sail the sea,
but the best ships are friendships,
may they always be!
""";
System.out.println("The multi line text example" + multiLineText);
}
Streams toList
Previously, to convert a stream to a list, we needed to use the collect
method with Collectors.toList()
. But now, in Java 17, we can directly call a toList()
method on stream object as seen below:
private static void countryStreamToList() {
Stream<String> countryStream = Stream.of("Germany", "Georgia", "Bulgaria");
List<String> countryList = countryStream.toList();
for (String country : countryList) {
System.out.println(country);
}
}
These are the must-know features for Java developers in their daily work. In the next blog, we will look at other performance improvement features introduced in Java 17 LTS.
Until then, happy coding.
Opinions expressed by DZone contributors are their own.
Comments