java 中出现异常后继续的更好方法
Better way to continue after exceptions in java
假设我必须从一个文件中读取,然后从中构造一个 java 对象。
PersonData p = new PersonData();
p.setName(readTokenAsString());
p.setAge(AgeConverter.createFromDateOfBirth(readTokenAsString())); // this throws a checked exception if the date of birth is mal-formed.
//... a list of methods that throws exception as AgeConverter
我想要的行为:如果一个属性有问题,忽略它并继续处理其他属性。
我能想到的解决办法:
try {
p.setAge1(...);
} catch (Exception e) {
//log and ignore
}
try {
p.setAge2(...);
} catch (Exception e) {
//log and ignore
}
//repeat for each attribute
问题:
是否有更好的方法来避免重复?也许是功能风格?
a) 如果我无法修改 PersonData
class.
,最好的方法是什么
b) 如果我可以重写 PersonData
class,最好的方法是什么?
如果你使用 Java 8 你可以做这样的事情。使用一种抛出 Exception
的方法创建您自己的功能接口
public interface MyConsumer<T> {
public void process(T t) throws Exception;
}
并创建一个 static
方法来使用该接口
public static <T> void setAndLogException(T value, MyConsumer<T> consumer) {
try {
consumer.process(value);
} catch (Exception e) {
// log exception
}
}
然后像setAndLogException(AgeConverter.createFromDateOfBirth(readTokenAsString()), p::setAge);
一样使用它
你也可以使用这个提供的解决方案:
此解决方案不会在编译阶段抱怨已检查的异常。
它会是这样的:
public static void ignoringExc(RunnableExc r) {
try { r.run(); } catch (Exception e) { }
}
@FunctionalInterface public interface RunnableExc { void run() throws Exception; }
然后:
PersonData p = new PersonData();
ignoringExc(() -> p.setName(readTokenAsString()));
...
鉴于您当前的声明,我将按如下方式进行。
定义一个 @FunctionalInterface
,您可以向其传递 I/O 逻辑:
@FunctionalInterface
public interface CheckedSupplier<T> {
T getValue() throws Exception;
}
定义一个使用 @FunctionaInterface
:
的实用方法
public static final <T> T getValueWithDefault(CheckedSupplier<T> supplier, T defaultValue) {
try {
return supplier.getValue();
} catch (Exception e){
return defaultValue;
}
}
使用实用方法如下:
PersonData p = new PersonData();
p.setName(getValueWithDefault(() -> readTokenAsString(), "default"));
p.setAge(getValueWithDefault(() -> AgeConverter.createFromDateOfBirth(readTokenAsString()), 0));
无论您是否要修改 PersonData
class 天气,这都可以解决问题。
假设我必须从一个文件中读取,然后从中构造一个 java 对象。
PersonData p = new PersonData();
p.setName(readTokenAsString());
p.setAge(AgeConverter.createFromDateOfBirth(readTokenAsString())); // this throws a checked exception if the date of birth is mal-formed.
//... a list of methods that throws exception as AgeConverter
我想要的行为:如果一个属性有问题,忽略它并继续处理其他属性。
我能想到的解决办法:
try {
p.setAge1(...);
} catch (Exception e) {
//log and ignore
}
try {
p.setAge2(...);
} catch (Exception e) {
//log and ignore
}
//repeat for each attribute
问题:
是否有更好的方法来避免重复?也许是功能风格?
a) 如果我无法修改 PersonData
class.
,最好的方法是什么
b) 如果我可以重写 PersonData
class,最好的方法是什么?
如果你使用 Java 8 你可以做这样的事情。使用一种抛出 Exception
public interface MyConsumer<T> {
public void process(T t) throws Exception;
}
并创建一个 static
方法来使用该接口
public static <T> void setAndLogException(T value, MyConsumer<T> consumer) {
try {
consumer.process(value);
} catch (Exception e) {
// log exception
}
}
然后像setAndLogException(AgeConverter.createFromDateOfBirth(readTokenAsString()), p::setAge);
你也可以使用这个提供的解决方案:
此解决方案不会在编译阶段抱怨已检查的异常。 它会是这样的:
public static void ignoringExc(RunnableExc r) {
try { r.run(); } catch (Exception e) { }
}
@FunctionalInterface public interface RunnableExc { void run() throws Exception; }
然后:
PersonData p = new PersonData();
ignoringExc(() -> p.setName(readTokenAsString()));
...
鉴于您当前的声明,我将按如下方式进行。
定义一个 @FunctionalInterface
,您可以向其传递 I/O 逻辑:
@FunctionalInterface
public interface CheckedSupplier<T> {
T getValue() throws Exception;
}
定义一个使用 @FunctionaInterface
:
public static final <T> T getValueWithDefault(CheckedSupplier<T> supplier, T defaultValue) {
try {
return supplier.getValue();
} catch (Exception e){
return defaultValue;
}
}
使用实用方法如下:
PersonData p = new PersonData();
p.setName(getValueWithDefault(() -> readTokenAsString(), "default"));
p.setAge(getValueWithDefault(() -> AgeConverter.createFromDateOfBirth(readTokenAsString()), 0));
无论您是否要修改 PersonData
class 天气,这都可以解决问题。