6
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Java] OptionalやStreamで例外を投げたい

Last updated at Posted at 2015-11-03

目的

  • Optional や Stream の map() などで、チェック例外を投げたいことがある(よね?)
  • でも標準の仕様だとチェック例外を投げることはできない
  • とりあえず、お試しでチェック例外を投げられる Optional もどきと Stream もどきを作って試してみよう(無意味)
  • ちなみにタグを見てもらえばわかると思いますが、実用性も皆無だと思います

【2015-11-04 追記】
結構書き直しました。サンプルソースもつけてみた。

Stream もどき

標準の java.util.stream.Stream はインタフェースなので、それを実装しようと思ったけど、少しずつ違うのでよく似た別のクラスを作成します。

まずはインタフェースを追加。例外を投げることのできる Consumer もどきと Function もどき。

Consumer2.java
import java.util.function.Consumer;

@FunctionalInterface
public interface Consumer2<T, E extends Exception> extends Consumer<T> {

	@Override
	default void accept(T t) {
		try {
			accept0(t);

		} catch (Exception e) {
			Stream2.sneakyThrows(e);
		}
	}

	void accept0(T t) throws E;
}
Function2.java
import java.util.function.Function;

@FunctionalInterface
public interface Function2<T, R, E extends Exception> extends Function<T, R> {

	@Override
	default R apply(T t) {
		try {
			return apply0(t);

		} catch (Exception e) {
			Stream2.sneakyThrows(e);
			// NOTREACHED
			throw new AssertionError();
		}
	}

	R apply0(T t) throws E;
}

Stream もどき。
チェック例外をうまく通せなかったので、かなり強引にスローしています。

Stream2.java
// import 文は省略

public class Stream2<E> implements AutoCloseable {
	/** 元となる Stream */
	private final Stream<E> base;

	/** Stream から Stream2 を生成 */
	public static <E> Stream2<E> of(Stream<E> base) {
		return new Stream2<E>(base);
	}

	/** コンストラクタ */
	private Stream2(Stream<E> base) {
		this.base = Objects.requireNonNull(base);
	}

    // ...

	/** 変換 */
	public <R, T extends Exception> Stream2<R> map(Function2<? super E, ? extends R, T> mapper) throws T {
		return of(base.map(mapper));
	}

	/** 処理 */
	public <T extends Exception> void forEach(Consumer2<? super E, T> action) throws T {
		base.forEach(action);
	}

	/** 無理やり例外を投げる */
	public static <E extends Exception> void sneakyThrows(Exception exception) throws E {
		@SuppressWarnings("unchecked")
		E e = (E) exception;
		throw e;
	}

    // (あとは省略。実際には実装してます)
}
Stream2Test.java
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class Stream2Test {

	public static void main(String[] args) {
		List<String> names = Arrays.asList("Alfa", "Bravo", "Charlie");

		// チェック例外を投げないならは、try - catch は不要
		Stream2<String> stream1 = Stream2.of(names.stream());
		stream1.forEach(name -> {
			System.out.println(name);
		});

		// チェック例外を外側でキャッチ
		try {
			Stream2<String> stream2 = Stream2.of(names.stream());
			stream2.forEach(name -> {
				method(name);
			});

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private static String method(String name) throws IOException {
		if (name.startsWith("C")) {
			throw new IOException(name);
		} else {
			System.out.println(name);
			return name;
		}
	}
}

実行結果。

Alfa
Bravo
Charlie
Alfa
Bravo
java.io.IOException: Charlie
	at Stream2Test.method(Stream2Test.java:30)
	at Stream2Test.lambda$1(Stream2Test.java:20)
	at Consumer2.accept(Consumer2.java:9)
	at java.util.Spliterators$ArraySpliterator.forEachRemaining(Unknown Source)
	at java.util.stream.ReferencePipeline$Head.forEach(Unknown Source)
	at Stream2.forEach(Stream2.java:99)
	at Stream2Test.main(Stream2Test.java:19)

Optional もどき

標準の java.util.Optional は final クラスで継承できないので、ソースを参考にしてやはり新規に作ってみる。

Optional2.java
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;

/** 例外を投げられる Optional もどき */
public final class Optional2<T> {

	/** 空の Optional2 */
	private static final Optional2<?> EMPTY = new Optional2<>(null);

	/** 値 */
	private final T value;

	/** コンストラクタ */
	private Optional2(T value) {
		this.value = value;
	}

	/** null でない Optional2 を生成 */
	public static <T> Optional2<T> of(T value) {
		Objects.requireNonNull(value);
		return new Optional2<>(value);
	}

	/** 値がある場合に変換を行う */
	public <U, E extends Exception> Optional2<U> map(Function2<? super T, ? extends U, E> mapper) throws E {
		Objects.requireNonNull(mapper);
		if (!isPresent()) {
			return empty();
		} else {
			return Optional2.ofNullable(mapper.apply(value));
		}
	}

    // (あとは省略。実際には実装してます)
}

呼び出してみます。

Optional2Test.java
import java.io.IOException;

public class Optional2Test {

	public static void main(String[] args) {

		// チェック例外を投げないならは、try - catch は不要
		String s1 = Optional2.of("Charlie")
				.map(s -> s + s)
				.orElse("null");
		System.out.println(s1);

		// チェック例外を外側でキャッチ
		try {
			Optional2<String> opt = Optional2.of("Charlie");
			String s2 = opt.map(Optional2Test::method)
					.orElse("null");
			System.out.println(s2);

		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	private static String method(String name) throws IOException {
		if (name.startsWith("C")) {
			// チェック例外を投げる
			throw new IOException(name);
		} else {
			System.out.println(name);
			return name;
		}
	}
}

実行結果。

CharlieCharlie
java.io.IOException: Charlie
	at Optional2Test.method(Optional2Test.java:29)
	at Function2.apply(Function2.java:9)
	at Optional2.map(Optional2.java:84)
	at Optional2Test.main(Optional2Test.java:16)

サンプル

gist:サンプルソース

6
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?