ラムダ式の中で例外が発生する場合は厄介なもので、何とかしようとするならラップに近い形で自分で用意するしかないみたい。
Consumer 、Function 、Predicate これらの例外捕捉処理バージョンを作っておけばかなり便利かもしれません。
import java.io.Serializable;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
ThrowableConsumer
@FunctionalInterface
public interface ThrowableConsumer<T> extends Serializable{
void accept(T t) throws Exception;
default Consumer<T> andThen(Consumer<? super T> after, BiConsumer<T, Exception> onCatch){
Objects.requireNonNull(after);
return (T t)->{
try{
accept(t);
}catch(Exception e){
onCatch.accept(t, e);
}
after.accept(t);
};
}
ThrowableConsumer 生成.
@param consumer<T>
@param onCatch
@return<T>
public static <T> Consumer<T> of(ThrowableConsumer<T> consumer, BiConsumer<T, Exception> onCatch){
return t->{
try{
consumer.accept(t);
}catch(Exception ex){
onCatch.accept(t, ex);
}
};
}
ThrowableConsumer 生成(外に例外スロー).
@param consumer<T>
@return<T>
public static <T> Consumer<T> of(ThrowableConsumer<T> consumer){
return t->{
try{
consumer.accept(t);
}catch(Throwable ex){
throw new RuntimeException(ex);
}
};
}
}
import java.io.Serializable;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;
ThrowableFunction
@FunctionalInterface
public interface ThrowableFunction<T, R> extends Serializable{
R apply(T t) throws Exception;
default <V> Function<V, R> compose(Function<? super V, ? extends T> before, BiFunction<V, Exception, R> onCatch){
Objects.requireNonNull(before);
return (V v)->{
try{
return apply(before.apply(v));
}catch(Exception e){
return onCatch.apply(v, e);
}
};
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after, BiFunction<T, Exception, ? extends V> onCatch){
Objects.requireNonNull(after);
return (T t)->{
try{
return after.apply(apply(t));
}catch(Exception e){
return onCatch.apply(t, e);
}
};
}
static <T> Function<T, T> identity(){
return t -> t;
}
ThrowableFunction 生成.
@param function<T, R>
@param onCatch
@return<T, R>
public static <T, R> Function<T, R> of(ThrowableFunction<T, R> function, BiFunction<T, Exception, R> onCatch){
return t->{
try{
return function.apply(t);
}catch(Exception e){
return onCatch.apply(t, e);
}
};
}
ThrowableFunction 生成(外に例外スロー).
@param function<T, R>
@return<T, R>
public static <T, R> Function<T, R> of(ThrowableFunction<T, R> function){
return t->{
try{
return function.apply(t);
}catch(Throwable ex){
throw new RuntimeException(ex);
}
};
}
}
import java.io.Serializable;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Predicate;
ThrowablePredicate
@FunctionalInterface
public interface ThrowablePredicate<T> extends Serializable{
boolean test(T t) throws Exception;
default Predicate<T> and(Predicate<? super T> other){
Objects.requireNonNull(other);
return (t)->{
try{
return test(t) && other.test(t);
}catch(Exception e){
return false;
}
};
}
default Predicate<T> and(Predicate<? super T> other, BiFunction<T, Exception, Boolean> onCatch){
Objects.requireNonNull(other);
return (t)->{
try{
return test(t) && other.test(t);
}catch(Exception e){
return onCatch.apply(t, e);
}
};
}
default Predicate<T> negate(){
return (t)->{
try{
return !test(t);
}catch(Exception e){
return false;
}
};
}
default Predicate<T> negate(BiFunction<T, Exception, Boolean> onCatch){
return (t)->{
try{
return !test(t);
}catch(Exception e){
return !onCatch.apply(t, e);
}
};
}
default Predicate<T> or(Predicate<? super T> other){
Objects.requireNonNull(other);
return (t)->{
try{
return test(t) || other.test(t);
}catch(Exception e){
return false;
}
};
}
default Predicate<T> or(Predicate<? super T> other, BiFunction<T, Exception, Boolean> onCatch){
Objects.requireNonNull(other);
return (t)->{
try{
return test(t) || other.test(t);
}catch(Exception e){
return onCatch.apply(t, e);
}
};
}
static <T> Predicate<T> isEqual(Object targetRef){
return (null==targetRef) ? Objects::isNull : object -> targetRef.equals(object);
}
ThrowablePredicate 生成.
@param p<T>
@param onCatch
@return<T>
public static <T> Predicate<T> of(ThrowablePredicate<T> p, BiFunction<T, Exception, Boolean> onCatch){
return t->{
try{
return p.test(t);
}catch(Exception e){
return onCatch.apply(t, e);
}
};
}
ThrowablePredicate 生成(外に例外スロー).
@param p<T>
@return<T>
public static <T> Predicate<T> of(ThrowablePredicate<T> p){
return t->{
try{
return p.test(t);
}catch(Throwable ex){
throw new RuntimeException(ex);
}
};
}
}
これを使うものとして、
Javaで MACアドレスを抽出する - Oboe吹きプログラマの黙示録
の処理を書いてみましょう。
最初の NetworkInterface.getNetworkInterfaces() だけは、SocketException の捕捉を外側(呼出し側)で処理を書かなくては
ならないですが、
NetworkInterface の isUp() や、getHardwareAddress() で発生の Exception 捕捉処理は
ThrowableXxxxx . of メソッドに、ラムダで書くことができます。
特に、Predicate で、(t, error)->false と、問答無用に無視を指定できるのが良いです。
Collections.list(NetworkInterface.getNetworkInterfaces()).stream()
.filter(ThrowablePredicate.of(t->t.isUp(), (t, error)->false))
.forEach(ThrowableConsumer.of(nf->{
String address = Optional.ofNullable(nf.getHardwareAddress())
.map(e->IntStream.range(0, e.length).mapToObj(i->String.format("%02X", e[i])).collect(Collectors.joining(" "))
).orElse(null);
System.out.printf("%d,%d,%s,\"%s\",%s%n"
, nf.isLoopback() ? 1 : 0
, nf.isUp() ? 1 : 0
, nf.getName()
, nf.getDisplayName()
, address
);
}, (e, error)->{}));