How to handle exceptions coolly with Java 8 Stream or Optional

Problem: It's awkward to handle exceptions with lambda expressions

Are you using the Java8 Streams API? It's very convenient. The Streams API, or lambda expression, is very powerful.

Lambda is very powerful but poorly illustrated.java


Function<String, String> slice = x -> x.substring(3, 6);
System.out.println(slice.apply("abcdefghij")); // -> "def"

As many have pointed out, [^ 1] is incompatible with exception handling, and exceptions cannot be caught outside of lambda. (No, I think it's natural because it's a lump of processing with lambda.)

In the above example, if the character string is 3 characters or less, an error will occur, so let's insert exception handling so that it will be returned as it is when an error occurs.

Try Catch is not cool and nesting is deep and I want you to stop.java


Function<String, String> sliceAndCatch = x -> {
	try {
		return x.substring(3, 6);
	} catch (Exception e) {
		return x;
	}
};

System.out.println(sliceAndCatch.apply("abcdefghij")); // -> "def"
System.out.println(sliceAndCatch.apply("xy")); // -> "xy"

Wow, the nest is deep.

Also, in the case of a method that throws a checked exception, you have to try catch in the lambda, so you can not call hoge :: fuga that throws an exception with stream.map (hoge :: fuga), which makes you feel frustrated. .. If it is an unchecked exception, it can be retrieved at the timing of calling (try {stream.map (hoge :: fuga)} catch {~}), but it is not clean. There is also a library that wraps Stream and Optional, but it is relatively inconvenient.

Solution: I hope you can write in one line → You can write this way

I want to write the above example with one liner. If you pass two lambdas, the first lambda is normal processing, and the second lambda is exception handling, it will be smart. So, first of all, prepare a functional interface that throws an exception

Function that throws an exception.java


interface ThrowableFunction<T, R> {
	R apply(T t) throws Exception;
}

And define Try like this

The whole picture is coming into view.java


public <T, R> Function<T, R> Try(ThrowableFunction<T, R> onTry, BiFunction<Exception, T, R> onCatch) {
	return x -> {
		try {
			return onTry.apply(x);
		} catch (Exception e) {
			return onCatch.apply(e, x);
		}
	};
}

That alone allows for cool coding!

Cool.java


Function<String, String> coolSlice = Try(x -> x.substring(3, 6), (error, x) -> x);

System.out.println(coolSlice.apply("abcdefghij")); // -> "def"
System.out.println(coolSlice.apply("xy")); // -> "xy"

If the Consumer does the same,

For Consumer.java


interface ThrowableConsumer<T> {
	void accept(T t) throws Exception;
}

public <T> Consumer<T> Try(ThrowableConsumer<T> onTry, BiConsumer<Exception, T> onCatch) {
	return x -> {
		try {
			onTry.accept(x);
		} catch (Exception t) {
			onCatch.accept(t, x);
		}
	};
}

This is also cool!

I did it.java


Consumer<String> coolCatch = Try(x -> {System.out.println(Integer.valueOf(x));}, (error, x) -> error.printStackTrace());

coolCatch.accept("33"); //-> 33
coolCatch.accept("Hoge"); //-> java.lang.NumberFormatException: For input string: "Hoge"・ ・ ・

merit and demerit

The good thing about this method

Bad place

Application: The mechanism is simple but useful

Of course, you can also pass it as a method reference, so you can call it like this

Ordinary example.java


stream.flatMap(Try(this::calc, (x,y)->Stream.empty()));

If it accepts Function <T, R> even if it is not Stream, it can be Optional.

Optional.java


Optional<String> name = getName();
name.flatMap(Try( dao::getFindByName ,(x,y)->Optional.empty()));

Also when passing lambda to the interface

Homebrew interface.java


interface JisakuInterface{
	String Method(String Argument);
}

JisakuInterface m = str->"hoge";
JisakuInterface f = Try(str -> str+str,(x,y)->"b")::apply;

If you refer to the method, you can easily pass it with lambda. great.

And when I made oleore monads,

Monamodoki.java


// LogicalDeletable.of(null)To generate a logical delete with.
LogicalDeletable<LegacyData> record = getRecord(); 
//Those who made a mistake in conversion are treated as logical deletion
record.map(Try(Legacy::legacyTransform)) , (error,record) -> null));

So you can take exceptions.

I can't think of an example (4th time), but since the thrown content is passed to onCatch as an argument, all the functions that can be done with normal TryCatch should be possible (except for try-with-resource).

That's why everyone should catch the exception coolly.

[^ 1]: Qiita alone http://qiita.com/daylife/items/b977f4f29b1f8ced3a02, http://qiita.com/KIchiro/items/4fafd74c46d08275eb56, http://qiita.com/yoshi389111/items/c6b7d373a00f8fd3

Recommended Posts

How to handle exceptions coolly with Java 8 Stream or Optional
Handle exceptions coolly with Java 8 lambda expressions and Stream API
How to use java Optional
[Java] How to use Optional ②
[Java] How to use Optional ①
How to compile Java with VsCode & Ant
[java] Summary of how to handle char
How to remote debug Java 9 or later
How to handle sign-in errors with devise
[Java] Learn how to use Optional correctly
Java 9 Optional :: stream
Java8 / 9 Beginners: Stream API addiction points and how to deal with them
[Java] How to test for null with JUnit
[java] Summary of how to handle character strings
How to use Java framework with AWS Lambda! ??
How to use Java API with lambda expression
How to handle optional in Protocol Buffers (proto3)
How to avoid exceptions with Java's equals method
[Java] How to operate List using Stream API
How to call functions in bulk with Java reflection
List processing to understand with pictures --java8 stream / javaslang-
[Java] How to omit spring constructor injection with Lombok
How to deploy Java to AWS Lambda with Serverless Framework
[For beginners] How to operate Stream API after Java 8
[Java] How to encrypt with AES encryption with standard library
How to convert A to a and a to A using AND and OR in Java
How to build Java development environment with VS Code
[Java] How to start a new line with StringBuilder
[Java] How to use Map
How to lower java version
[Java] How to use Map
How to decompile apk file to java source code with MAC
Rewrite Java try-catch with Optional
How to uninstall Java 8 (Mac)
How to use trained model of tensorflow2.0 with Kotlin / Java
Java to play with Function
Java --How to make JTable
How to handle uploaded images
[Must-see for apprentice java engineer] How to use Stream API
How to minimize Java images
How to write java comments
How to use java class
[CQ Engine] I want to handle collections like Stream or .Net LINQ even in Java 7.
[Java] How to use removeAll ()
[Java] How to display Wingdings
[Java] How to use string.format
How to number (number) with html.erb
How to use Java Map
How to update with activerecord-import
How to set Java constants
Connect to DB with Java
Connect to MySQL 8 with Java
List processing to understand with pictures --java8 stream / javaslang --bonus
How to install java9 on elementaryOS Freya or Ubuntu 14.04 LTS
How to use Java variables
[Java] Introduction to Stream API
Java8 to start now ~ Optional ~
How to handle an instance
Differences in how to handle strings between Java and Perl
How to convert Java radix
[Java] How to implement multithreading