I love Java8's semantics. I use a lot of such code in my DAOs :
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();
}
}
It works well , but such code (try catch NoResultException ) scatters over my DAOs. And I have to catch Exception , which somehow lowers performance .
I wonder if it the best solution ? or any better solution , without try-catch ?
If it is not possible (because NoResultException is defined in JPA) , any shortcut to 'templatize' such workflow ?
Thanks.
As for your getters, don't use Optional. And try to design your classes so none of the members can possibly be null.
The Optional type was introduced in Java 8. It provides a clear and explicit way to convey the message that there may not be a value, without using null. When getting an Optional return type, we're likely to check if the value is missing, leading to fewer NullPointerExceptions in the applications.
Optional is a container object which may or may not contain a non-null value. You must import java. util package to use this class. If a value is present, isPresent() will return true and get() will return the value.
If course you can templatize it, using the magic of lambdas!
Start with an @FunctionalInterface
to define the lambda's contract:
@FunctionalInterface
public interface DaoRetriever<T> {
T retrieve() throws NoResultException;
}
This is a Single Method Interface (or SMI) that will encapsulate the behaviour of your method.
Now create a utility method to use the SMI:
public static <T> Optional<T> findOrEmpty(final DaoRetriever<T> retriever) {
try {
return Optional.of(retriever.retrieve());
} catch (NoResultException ex) {
//log
}
return Optional.empty();
}
Now, using an import static
in your calling code, your method above becomes:
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());
}
So here, () -> emp.get()...
is a lambda that captures the retrieval behaviour. The interface DaoRetriever
is allowed to throw a NoResultException
so the lambda is too.
Alternatively, I would use the other method of TypedQuery
- getResultList
- and change the code as follows:
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();
}
This has the advantage of being simpler, but the disadvantage of simply discarding other results if there are any.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With