在这篇文章中,我们将看到如何有效地使用Java 8 Optional
类来处理实时项目中的空指针异常。如何在不同的层中处理空指针,如controller layer, service layer,
和DAO layer
。
关于Java 8Optional类的关键点:
*null
references在历史上一直被引入编程语言中,一般用来表示没有一个值。
java.util.Optional
类来模拟一个值的存在或不存在。Optional. empty, Optional.of, and Optional.ofNullable
创建Optional
objects。Optional
class支持许多方法,如map, flatMap, and filter
,它们在概念上与流的方法相似。Optional
迫使你主动解开一个Optional,以处理没有值的情况;因此,你可以保护你的代码不发生意外的空指针异常。Optional
可以帮助你设计更好的API,在这些API中,用户只需阅读一个方法的签名,就可以知道是否需要一个Optional值。在这篇文章中,我们将看到如何在实时项目中使用Java 8的Optional性。Spring
和Hibernate
Framework创建CRUD操作为例。在典型的Spring MVC web application
中,有三个层,即Controller
、Service
和DAO
layer。
让我们看看Optional类API在每个层中的使用情况。
Optional
Class API在DAO
层的用法在DAO层,我们写代码从数据库中通过id or some
字段检索记录,基本上,我们不确定该记录是否存在,在这种情况下,该方法返回空引用。让我们写一段代码来避免这种null
pointer异常。
例子:
@Override
public Optional<User> getUserById(Integer userId) {
return Optional.ofNullable((User) sessionFactory.getCurrentSession()
.createCriteria(User.class).add(Restrictions.eq("userId", userId))
.uniqueResult());
}
@Override
public Optional<User> loadUserByUsername(String userName) {
Session session = sessionFactory.getCurrentSession();
Criteria criteria = session.createCriteria(User.class)
.add(Restrictions.eq("userName", userName))
.add(Restrictions.eq("enabled", true));
return Optional.ofNullable((User) criteria.uniqueResult());
}
请注意,使用Optional.ofNullable()
静态工厂方法,如果存在就返回值,否则就返回一个空的Optional
实例。
Optional
类API在Service
Layer中的用法让我们看看如何在Service Layer
中使用这段代码。在Service Layer
中,我们需要处理该记录是否存在。如果它存在,则返回对象,否则抛出一个异常或向客户报告错误。
@Override
@Transactional
public User loadUserByUsername(String userName) {
return userDao.loadUserByUsername(userId).orElseThrow(
() -> new ResourceNotFoundException(Integer.valueOf(userId)));
}
@Override
@Transactional
public void deleteUser(Integer userId) throws BaseException, ResourceNotFoundException {
if (userId == null) {
throw new BaseException(" Request param can't be null . " + userId);
}
final User user = userDao.getById(userId)
.orElseThrow(() -> new UnauthorizedRequestException("User not exist"));
user.setEnabled(false);
userDao.update(user);
}
@Override
@Transactional(readOnly = true)
public User getUserById(Integer userId) throws BaseException {
if (userId == null) {
throw new BaseException(" Request param can't be null . " + userId);
}
return userDao.getById(userId).orElseThrow(
() -> new ResourceNotFoundException(Integer.valueOf(userId)));
}
请注意,使用orElseThrow()
方法,如果存在则返回值,否则抛出一个异常。在上面的例子中,我们使用了Optional.orElseThrow()
方法和一个lambda表达式。
Optional
API在Controller
Layer中的用法我们假设UserService
interface被注入到UserController
class中,那么我们可以直接在e1d34d1中使用UserService
interface方法。
在这个例子中,注意isPresent()
方法在Optional
Class中的使用情况。
@RequestMapping(path = "/users/{userId}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody ResponseEntity<User> getUser(
@PathVariable("userId") String userId) {
Optional<User> user = userService.getUser(userId);
if (user.isPresent()) {
return ResponseEntity.ok().body(user.get());
}
return ResponseEntity.badRequest().build();
}
还有一个用例是,如果你已经使用了Generic Dao layer
,那么Optional
Class的API可以像这样使用。
@Override
public Optional<T> getById(final K id) {
try {
return Optional.ofNullable((T) getSession().get(getType(), id));
} catch (final RuntimeException re) {
LOGGER.error("get failed", re);
throw re;
}
}
让我们来创建一个用户的POJO类。
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.codehaus.jackson.annotate.JsonManagedReference;
@Entity
@Table(name = "user")
public class User {
private int userId;
private String userName;
private String password;
private boolean enabled;
private String firstName;
private String lastName;
private Long dateCreated;
private Long dateUpdated;
private long lastAccess;
private long lastLogin;
private String email;
public User() {
}
public User(int userId, String userName, String password, boolean enabled
) {
super();
this.userId = userId;
this.userName = userName;
this.password = password;
this.enabled = enabled;
}
public User(String userName, String password, boolean enabled,
String firstName, String lastName, Long dateCreated, Long dateUpdated,
long lastAccess, long lastLogin, String email) {
super();
this.userName = userName;
this.password = password;
this.enabled = enabled;
this.firstName = firstName;
this.lastName = lastName;
this.dateCreated = System.currentTimeMillis();
this.dateUpdated = System.currentTimeMillis();
this.lastAccess = lastAccess;
this.lastLogin = lastLogin;
this.email = email;
}
@Id
@Column(name = "userId")
@GeneratedValue(strategy = GenerationType.IDENTITY)
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public long getLastAccess() {
return lastAccess;
}
public void setLastAccess(long lastAccess) {
this.lastAccess = lastAccess;
}
public long getLastLogin() {
return lastLogin;
}
public void setLastLogin(long lastLogin) {
this.lastLogin = lastLogin;
}
public Long getDateCreated() {
return dateCreated;
}
public void setDateCreated(Long dateCreated) {
this.dateCreated = dateCreated;
}
public Long getDateUpdated() {
return dateUpdated;
}
public void setDateUpdated(Long dateUpdated) {
this.dateUpdated = dateUpdated;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
创建UserService.java接口和它的实现类UserServiceImpl.java。
public interface UserService {
User saveOrUpdateUser(User user) throws BadRequestException;
boolean checkUserExist(String userName);
Optional<User> loadUserByUsername(String userName);
void deleteUser(int userId) throws BaseException, ResourceNotFoundException;
List<UserResponse> getUsers() throws BaseException;
Optional<User> getUserById(Integer userId) throws BaseException;
}
@Service
public class UserService implements IUserService {
@Inject
private IUserDao userDao;
@Inject
private PasswordEncoder passwordEncoder;
@Inject
private RoleService roleService;
@Override
@Transactional(readOnly = false)
public User saveOrUpdateUser(User user) throws BadRequestException {
validateUser(user);
this.userDao.save(user);
return user;
}
private void validateUser(UserRequest userRequest) throws BadRequestException {
if (userRequest == null) {
throw new BadRequestException(" User object can't be null.");
}
if (userRequest.getEmail() == null) {
throw new BadRequestException(" User email can't be null.");
}
if (userRequest.getFirstName() == null) {
throw new BadRequestException(" User First name can't be null.");
}
if (userRequest.getLastName() == null) {
throw new BadRequestException(" User last name can't be null.");
}
if (userRequest.getPassword() == null) {
throw new BadRequestException(" Password can't be null.");
}
}
@Override
@Transactional
public boolean checkUserExist(String userName) {
final long count = userDao.checkUserExist(userName);
return count > 0;
}
@Override
@Transactional
public User loadUserByUsername(String userName) {
return userDao.loadUserByUsername(userId).orElseThrow(
() -> new ResourceNotFoundException(Integer.valueOf(userId)));
}
@Override
@Transactional
public void deleteUser(Integer userId) throws BaseException, ResourceNotFoundException {
if (userId == null) {
throw new BaseException(" Request param can't be null . " + userId);
}
final User user = userDao.getById(userId)
.orElseThrow(() -> new UnauthorizedRequestException("User not exist"));
user.setEnabled(false);
userDao.update(user);
}
@Override
@Transactional(readOnly = true)
public List<UserResponse> getUsers() throws BaseException {
final List<UserResponse> listOfUsers = userDao.getUsers();
if (listOfUsers == null) {
throw new BaseException("Users not exist in database");
}
return listOfUsers;
}
@Override
@Transactional(readOnly = true)
public User getUserById(Integer userId) throws BaseException {
if (userId == null) {
throw new BaseException(" Request param can't be null . " + userId);
}
return userDao.getById(userId).orElseThrow(
() -> new ResourceNotFoundException(Integer.valueOf(userId)));
}
}
让我们创建UserDao.java接口和它的实现UserDaoImpl.java。
public interface UserDao {
User saveOrUpdateUser(UserRequest userRequest) throws BadRequestException;
boolean checkUserExist(String userName);
Optional<User> loadUserByUsername(String userName);
void deleteUser(int userId) throws BaseException, ResourceNotFoundException;
List<UserResponse> getUsers() throws BaseException;
Optional<User> getUserById(Integer userId) throws BaseException;
}
@Repository
public class UserDao implements UserDao{
@Autowired
private SessionFactory sessionFactory;
@Override
public void saveOrUpdateUser(User user) {
Session session = sessionFactory.getCurrentSession();
session.saveOrUpdate(user);
}
@Override
public Optional<User> getUserById(Integer userId) {
return Optional.ofNullable((User) sessionFactory.getCurrentSession()
.createCriteria(User.class).add(Restrictions.eq("userId", userId))
.uniqueResult());
}
@Override
public Optional<User> loadUserByUsername(String userName) {
Session session = sessionFactory.getCurrentSession();
Criteria criteria = session.createCriteria(User.class)
.add(Restrictions.eq("userName", userName))
.add(Restrictions.eq("enabled", true));
return Optional.ofNullable((User) criteria.uniqueResult());
}
@Override
public long checkUserExist(String userName) {
Session session = sessionFactory.getCurrentSession();
Criteria criteria = session.createCriteria(User.class)
.add(Restrictions.eq("userName", userName))
.add(Restrictions.eq("enabled", true));
criteria.setProjection(Projections.rowCount());
return (Long) criteria.uniqueResult();
}
@Override
public List<UserResponse> getUsers(){
Session session = sessionFactory.getCurrentSession();
final List<UserResponse> users = new ArrayList<>();
// get users code here
return users;
}
@Override
public void deleteUser(User user){
Session session = sessionFactory.getCurrentSession();
session.delete(user);
}
}
在这篇文章中,我们已经学会了如何使用Java 8的Optional类来处理NullPointerException
在不同的层,如controller, service and DAO
层。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
内容来源于网络,如有侵权,请联系作者删除!