It's surprisingly difficult to express failure when dealing with Java. Optional has appeared in Java 8 and it has become much easier to handle, but it is still compared to other languages. I've been worried about it all these days, so here's a summary of how I handle my own mistakes.
Java 8 or later (later version is better)
Speaking of the royal road, it is a pattern to return Null if it can not be acquired. Until Optional appeared in Java8, it was natural to check Null, but it seems that Optional has changed. I try not to treat it too much in Null as a return value in the application.
I can't help but leave a lot of old processing, so I handle it with Null until the day when it can be refactored.
Main.java
public class Main {
public static void main(String[] args) {
String first = getFirstArg(args);
if(first == null) {
System.out.println("There are no arguments");
return;
}
System.out.print("The first argument is[ " + first + "]is");
}
private static String getFirstArg(String[] args) {
if(args == null || args.length == 0) {
return null;
}
return args[0];
}
}
This is also a royal road.
I think it often expresses ʻis has
can. In this case, the primitive type
boolean is often used rather than the Object type
Boolean. Since it can be expressed by
true``false` instead of the presence or absence of data, this check is used as it will remain in the future.
Main.java
public class Main {
public static void main(String[] args) {
if(hasFirstArg(args)) {
System.out.println("There are arguments");
} else {
System.out.println("There are no arguments");
}
}
private static boolean hasFirstArg(String[] args) {
return args != null && 0 < args.length;
}
}
It is also possible to express an error by raising an exception. If the purpose of the method cannot be achieved when the process is created as an external library, it is used, but otherwise it is not used much. If it doesn't seem to be a problem, I often throw it from the bottom and throw it as it is, but I'm careful not to throw it away in the end.
I think it's a difficult expression because it's thrown away or something, but I want to use it well. The difficulty is that error control is difficult, but ...
Main.java
public class Main {
public static void main(String[] args) {
try {
System.out.println("The first argument is[" + getFirstArg(args) + "]is");
} catch(NullPointerException e) {
System.out.println("Argument is null");
} catch(IllegalArgumentException e) {
System.out.println("Illegal argument");
}
}
private static String getFirstArg(String[] args) {
if(args == null) {
throw new NullPointerException();
}
if(args.length == 0) {
throw new IllegalArgumentException();
}
return args[0];
}
}
If you put this out in a review, you won't be able to complain even if you get stung.
I think that expressing with Optional that came out earlier is standard if it is the current basic function of Java.
The feature is that it is easy to understand that this return value may not exist by using Optional.
With the expressions so far, it is not possible to tell at a glance whether it is successful or unsuccessful, and it is not known until Null is checked, and if you forget to check Null and access it, everyone will love NullPointerException
.
We are very pleased to be able to get out of this situation with the advent of Optinal.
For details, I have published an article on Qiita, so please have a look there. https://qiita.com/tasogarei/items/18488e450f080a7f87f3 https://qiita.com/tasogarei/items/f289d125660af6fe5ba6
Main.java
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> arg = getFirstArg(args);
arg.ifPresent(first ->System.out.print("The first argument is[ " + first + "]is"));
}
private static Optional<String> getFirstArg(String[] args) {
if(args == null || args.length == 0) {
return Optional.empty();
}
return Optional.ofNullable(args[0]);
}
}
However, since ʻifPresentOrElse does not exist in Java8, it may not be possible to express the processing when it succeeds and when it fails (first appeared in Java9). In the case of Java8, you have to do the sad thing of checking the existence with ʻis Present
and writing the process with ʻif`.
arg.ifPresentOrElse(first -> System.out.println("The first argument is[ " + first + "]is"),
() -> System.out.println("No arguments"));
Alternatively, you can use map
and ʻor Else (Get)` to convert to a specific type for processing.
Overdoing it can reduce readability in Optional Nest Hell, so it's harder than you think to write it well.
Main.java
import java.util.Optional;
public class Main {
public static void main(String[] args) {
Optional<String> arg = getFirstArg(args);
System.out.println(arg.map(first -> "The first argument is[" + first + "]is").orElse("No arguments"));
}
private static Optional<String> getFirstArg(String[] args) {
if(args == null || args.length == 0) {
return Optional.empty();
}
return Optional.ofNullable(args[0]);
}
}
With the advent of Optional, it has become possible to break away from null, but Optional can tell whether it succeeded or failed, but cannot explain why. That's where Either comes in.
Either is supported in some languages, but unfortunately it is not supported in Java. Although it is a level that can be implemented by myself, it is implemented in a library called vavr (there are many other functions, but this time I will use it for Either purpose).
【official】 http://www.vavr.io/
So let's add a dependency to pom.xml and implement it.
pom.xml
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr</artifactId>
<version>0.9.2</version>
</dependency>
Main.java
import java.util.Optional;
import io.vavr.control.Either;
public class Main {
public static void main(String[] args) {
Either<Integer,String> arg = getFirstArg(args);
if(arg.isRight()) {
System.out.println("The first argument is[" + arg.get() + "]is");
} else {
System.out.println("Argument error. Type" + arg.getLeft());
}
}
private static Either<Integer,String> getFirstArg(String[] args) {
if(args == null) {
return Either.left(1);
}
if(args.length == 0) {
return Either.left(2);
}
return Either.right(args[0]);
}
}
Either is successful if there is a value in Right and fails if there is a value in Left. Since it is allowed to have a value in only one of them, there is no problem if you can confirm which one has the value for success or failure.
However, in Java, there is no such thing as a Scala match, so it makes me sad to express which one has a value with if. Maybe you can do something similar to match, but I don't know yet.
However, now it is possible to express the type of failure, which makes it easy to change the process, get the value while expressing the error, and so on.
Recently, I've started using Either mainly with Optional, and I'm implementing it while worrying about various things. It's difficult to express failure, but please let me know if there is a good implementation method.
Recommended Posts