The Java release cycle has changed, and as of January 2019, the latest version of Java is as early as 11. Grammatic improvements are also progressing, and modern Java styles are changing. In this article, I'd like to summarize the modern style of Java programming in the Java 11 era.
Please note that it probably includes the subjectivity of the author.
--Actively use var
.
It is a type declaration of local variables by var
introduced in Java 10, but basically it is good to use it positively when it can be used. Many modern languages use similar type inference, but I don't hear that it was a problem.
It's reasonable to say that for highly trained Java programmers, the IDE will auto-complete the type definitions on the left side, so it's not convenient, but only when reading code, the number of characters on the left side of Java There is redundancy in the number of, which significantly impairs readability.
// before
Owner owner = new Owner();
List<Pet> pets = List.of(new Pet("pochi"), new Pet("tama"));
// after
var owner = new Owner();
var pets = List.of(new Pet("pochi"), new Pet("tama"));
The above example is not a big deal, but Java class names tend to be long when including generics, so it's often easier to read if you use var
to reduce the amount of information.
unmodifiable
--Make collections as immutable as possible where they can.
Java's standard collection library doesn't have an immutable interface like ʻImmutableList`, but you can make an exception when you try to change an element. In order to prevent unexpected changes in elements, it is better to make the parts that can be made immutable as immutable as possible.
//Factory methods added in Java 9 generate immutable collections
List.of(1, 2, 3); // unmodifiable
Set.of(1, 2, 3); // unmodifiable
Map.of("keyA", "valueA", "keyB", "ValueB"); // unmodifiable
//The Collections class provides a method that returns an immutable view of the collection.
Collections.unmodifiableList(modifiableList); // unmodifiable
//Factory methods added in Java 10 also allow you to create immutable views of existing collections
List.copyOf(modifiableList); // unmodifiable
//Java 10 adds a method to convert to an immutable collection as a Stream Collector
modifiableList.stream().collect(Collectors.toUnmodifiableList());
Stream API
--Process by Stream API without using for statement as much as possible.
With the advent of the Stream API in Java 8, the for statement has almost disappeared. The Stream API's declarative description is readable and performance-friendly when used well, so it's best to use the Stream API for collection operations, except in exceptional cases.
var beforeList = List.of("a", "b", "c");
// before
var afterList1 = new ArrayList<String>();
for (var str : beforeList) {
afterList.add(str.toUpperCase());
}
// after
var afterList2 = beforeList
.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
Null
Optional
--If null
can be returned as the return value of the method, return it as ʻOptional` type.
Java 8 added the ʻOptional type to indicate that the value may be
null. There is no reason not to use this, so if
null can be returned, always return it as type ʻOptional
instead of returning null
directly.
Optional<String> getName() {
return Optional.ofNullable(this.name);
}
It seems that ʻOptonal` is mainly supposed to be used as the return value of the method, so basically it is better not to use it in the argument or field of the method.
Nullability
--null
Whether or not it is possible is expressed by annotation.
One of the merits of introducing Kotlin is that it is null-safe, but Java also has a mechanism to partially realize it, which is a declaration of null possibility by annotation. It was never adopted as a Java standard feature, so it requires the introduction of some third-party library, but it is a widely used mechanism.
For example, using the annotations provided by Spring Framework from version 5, the following expressions are possible.
public @Nullable Pet getPetByName(@NonNull String name) {
//Null must not be passed in the argument name
//The return value Pet can be null (usually Optional)<Pet>Is better)
}
This allows the IDE to statically check for nullability in advance.
By the way, even when using Java code from Kotlin, there is an advantage that it is determined that it is a null non-allowable type by adding these annotations.
reference)
Objects.requireNonNull
--Method null non-nullable arguments are checked for null at an early timing using the ʻObjects.requireNonNull` method.
Annotations that represent nullability can prevent nulls from being mixed in to some extent, but since they are only static analysis, they are powerless if nulls are mixed in at runtime. In order to detect null contamination at runtime early, null check inside the method is necessary after all.
With ʻObjects.requireNonNull` introduced in Java 7, you can do null checking concisely, so it's a good idea to actively use it.
Pet(@NonNull String name, @NonNull LocalDate birthdate) {
this.name = Objects.requireNonNull(name);
this.birthdate = Objects.requireNonNull(birthdate);
}
By the way, in IntelliJ, by pressing Option + Enter on the variable with annotation such as @ NonNull
, the option to automatically enclose it in ʻObjects.requireNonNull` is displayed, so use this. It is efficient to do.
try-with-resources
--Use try-with-resources wherever resources need to be closed.
Java 7 introduced a try-with-resource mechanism to make it easier to close resources. For resources that must be closed regardless of the success or failure of the process, such as database connections, it is always better to use the try-with-resource mechanism to perform the close process.
// before
FileInputStream inputStream1 = null;
try {
inputStream1 = new FileInputStream("foo.txt");
inputStream1.read();
} finally {
if (inputStream1 != null) {
try {
inputStream1.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// after
try (var inputStream2 = Files.newInputStream(Path.of("foo.txt"))) {
inputStream2.read();
}
--Use Date and Time API. --Do not use old classes such as Date class, Calendar class, SimpleDateFormat class unless there is a special reason.
The Date and Time API introduced in Java 8 can replace almost all of the old Date, Calendar, and SimpleDateFormatter classes. Unless you have a specific reason, you shouldn't use the old class.
// before
var date = new Date();
var simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd");
System.out.println(simpleDateFormat.format(date));
// after
var localDate = LocalDate.now();
var dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
System.out.println(dateTimeFormatter.format(localDate));
It can be said that libraries such as Joda-Time, which was used to eliminate the difficulty of using the old classes, have also finished their role.
-Date and Time API Review-Qiita
--Preferentially use the java.nio.file
package class (NIO2) over the java.io
package class (Java I / O).
With NIO2 introduced in Java 7, Java's file manipulation API is new. Basically, it is better to go with the policy of using the new API instead of using the old API as much as possible.
// before
var dir = new File("/tmp/dir");
var succeeded = dir.mkdir();
if (succeeded) {
try {
new File(dir, "foo.txt").createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
// after
try {
var directory = Files.createDirectory(Path.of("/tmp/dir2"));
Files.createFile(directory.resolve("foo.txt"));
} catch (IOException e) {
e.printStackTrace();
}
Try to use Path.of (..)
and Files.xxx
instead ofnew File (..)
.
-Java NIO2 review memo-- Qiita --Rewrite the code of java.io.File using java.nio.Path and java.nio.Files --Qiita
Added as soon as I understand ...
Recommended Posts