我喜欢Java8的语义。我在我的DAO中使用了很多这样的代码:
public Optional<User> findBy(String username) {
try {
return Optional.of(
emp.get().createQuery("select u from User u where u.username = :username" , User.class)
.setParameter("username" , username)
.setMaxResults(1)
.getSingleResult()
);
} catch (NoResultException e) {
return Optional.empty();
}
}
它运行良好,但是这样的代码(尝试捕获NoResultException)会分散在我的DAO上。我必须捕捉异常,这会以某种方式降低性能。
我想知道它是否是最好的解决方案?或任何更好的解决方案,没有try-catch?
如果不可能(因为在JPA中定义了NoResultException),任何&#39;模板化&#39;的快捷方式。这样的工作流
感谢。
答案 0 :(得分:26)
如果当然你可以使用lambdas的魔法来模板化它!
从@FunctionalInterface
开始定义lambda的合同:
@FunctionalInterface
public interface DaoRetriever<T> {
T retrieve() throws NoResultException;
}
这是一个单一方法接口(或SMI),它将封装您方法的行为。
现在创建一个实用程序方法来使用SMI:
public static <T> Optional<T> findOrEmpty(final DaoRetriever<T> retriever) {
try {
return Optional.of(retriever.retrieve());
} catch (NoResultException ex) {
//log
}
return Optional.empty();
}
现在,在您的调用代码中使用import static
,您的上述方法将变为:
public Optional<User> findBy(String username) {
return findOrEmpty(() ->
emp.get().createQuery("select u from User u where u.username = :username", User.class)
.setParameter("username", username)
.setMaxResults(1)
.getSingleResult());
}
所以在这里,() -> emp.get()...
是一个捕获检索行为的lambda。允许interface DaoRetriever
抛出NoResultException
,因此lambda也是如此。
或者,我会使用TypedQuery
- getResultList
的其他方法 - 并按如下方式更改代码:
public Optional<User> findBy(String username) {
return emp.get().createQuery("select u from User u where u.username = :username", User.class)
.setParameter("username", username)
.setMaxResults(1)
.getResultList()
.stream()
.findFirst();
}
这样做的好处是更简单,但缺点是如果有的话,简单地丢弃其他结果。
答案 1 :(得分:3)
鲍里斯走在正确的轨道上,但它可以做得更好。我们需要更多的抽象。此转换与daos无关。
我们需要一个不同arities的系列或功能接口,它们将抛出异常的lambda转换为不抛出异常的lambda。 FunctionalJava(http://www.functionaljava.org/)执行此操作:
所以我们有一系列Try类:Try0,Try1等。
public interface Try0<A, Z extends Exception> {
A f() throws Z;
}
我们希望将其转换为不抛出异常的函数:
static public <A, E extends Exception> Supplier<Validation<E, B>> toSupplierValidation(final Try0<A, E> t) {
return () -> {
try {
return Validation.success(t.f());
} catch (Exception e) {
return Validation.fail((E) e);
}
};
}
请注意,验证在失败案例中是例外,如果成功则是常规值(https://functionaljava.ci.cloudbees.com/job/master/javadoc/)。如果您不关心异常,则可以将失败案例转换为空可选项和成功案例,以使值在可选项中。这个方法看起来像Boris,但没有dao引用(这是无关紧要的):
static public <A, E extends Exception> Supplier<Optional<A>> toSupplierOptional(final Try0<A, E> t) {
return () -> {
try {
return Optional.of(t.f());
} catch (Exception e) {
return Optional.empty();
}
};
}