java中异常后继续的更好方法

java中异常后继续的更好方法,java,orm,exception-handling,functional-programming,Java,Orm,Exception Handling,Functional Programming,假设我必须读取一个文件,然后从中构造一个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 me

假设我必须读取一个文件,然后从中构造一个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
@FunctionalInterface
public interface CheckedSupplier<T> {
    T getValue() throws Exception;
}
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));
问题:

try {
  p.setAge1(...);
} catch (Exception e) {
  //log and ignore
}

try {
  p.setAge2(...);
} catch (Exception e) {
  //log and ignore
}

//repeat for each attribute
@FunctionalInterface
public interface CheckedSupplier<T> {
    T getValue() throws Exception;
}
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));
有没有更好的方法来避免重复?也许是功能性风格

a) 如果我不能修改
PersonData
类,那么最好的方法是什么。

b) 如果我可以重写
PersonData
类,那么最好的方法是什么

如果您使用Java8,您可以执行类似的操作。用一个抛出异常的方法创建您自己的功能接口

public interface MyConsumer<T> {
    public void process(T t) throws 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()));
...

鉴于你目前的声明,我将按如下方式做

定义可以向其传递I/O逻辑的
@functional接口:

try {
  p.setAge1(...);
} catch (Exception e) {
  //log and ignore
}

try {
  p.setAge2(...);
} catch (Exception e) {
  //log and ignore
}

//repeat for each attribute
@FunctionalInterface
public interface CheckedSupplier<T> {
    T getValue() throws Exception;
}
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));
使用以下实用方法:

try {
  p.setAge1(...);
} catch (Exception e) {
  //log and ignore
}

try {
  p.setAge2(...);
} catch (Exception e) {
  //log and ignore
}

//repeat for each attribute
@FunctionalInterface
public interface CheckedSupplier<T> {
    T getValue() throws Exception;
}
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
类,这都可以实现

考虑到java的反射,一开始需要更多的努力,但从长远来看,AgeConverter将更加方便和可重用。createFromDateOfBirth(readTokenAsString())
是否应该修改此方法以消除异常?或者您可以将其包装到另一个吞咽异常的方法中?因此,您不需要到处尝试/捕获。如果您可以更新PersonData类,最好使其不可变,使用一个生成器类通过所有参数构造设置所有值您还可以使用此提供的解决方案:只需尝试即可。对于检查过的异常,编译器似乎仍然抱怨没有处理它。这帮助我理解了这个想法。但是,这仍然会有编译器错误。只要调用
AgeConverter.XXX
,就需要在调用方法中处理选中的异常。因此,我们需要一个
MySupplier
接口抛出异常来包装
AgeConverter.XXX
方法。(而不是环绕p.setAge方法)我最终使用了vavr的checked exception接口。这和你的想法基本上是一样的。