作用
可以简洁的完成参数检验,在进行业务逻辑代码前进行前置判断。并且避免了冗长的if语句。guava将所有检验的API都放置于Preconditions类中。
API
Preconditions类大致分为6种提供参数检验的方法,每种方法都有三个重载方法。重载方法的参数意义是:
- 仅有待校验的参数:抛出的异常中没有错误消息;
- 有一个Object对象作为额外参数:抛出的异常使用Object.toString() 作为错误消息;
- *有一个String对象作为额外参数,还有一个Object[]参数,这两个参数也是适用于异常错误消息的,处理的方式类似于String.format将Object的参数按顺序替换掉String中的占位符(如%s)
-
方法声明(不包括额外参数) 描述 检查失败时抛出的异常 checkArgument(boolean) 检查boolean是否为true,用来检查传递给方法的参数。 IllegalArgumentException checkNotNull(T) 检查value是否为null,该方法直接返回value,因此可以内嵌使用checkNotNull。。 NullPointerException checkState(boolean) 用来检查对象的某些状态。 IllegalStateException checkElementIndex(int index, int size) 检查index作为索引值对某个列表、字符串或数组是否有效。index>=0 && index<size *。 IndexOutOfBoundsException checkPositionIndex(int index, int size) 检查index作为位置值对某个列表、字符串或数组是否有效。index>=0 && index<=size *。 IndexOutOfBoundsException checkPositionIndexes(int start, int end, int size) 检查[start, end]表示的位置范围对某个列表、字符串或数组是否有效* IndexOutOfBoundsException
实例
如:我们在做登录操作的方法中,在未用前置条件前,代码可能会如下:
1 public User login(String userName,String password){ 2 if(StringUtils.isEmpty(userName) || StringUtils.isEmpty(password)){ 3 throw new RuntimeException("用户名或密码不能为空"); 4 } 5 User user = userService.queryUserByUserNameAndPassword(userName,password); 6 if(null == user){ 7 throw new RuntimeException("用户名或密码错误"); 8 } 9 //…………………………………………省略业务逻辑………………………………………… 10 }
当使用了Preconditions类后
public User login(String userName,String password){ Preconditions.checkArgument(!(StringUtils.isEmpty(userName) || StringUtils.isEmpty(password)),"用户名或密码不能为空"); User user = userService.queryUserByUserNameAndPassword(userName,password); Preconditions.checkNotNull(user,"用户名或密码错误"); //…………………………………………省略业务逻辑………………………………………… }
思考
相信大家也发现了,Preconditions类与Assert断言类的思想基本是一致的,通过这个思想,我们也可以实现属于自己的断言类从而提升自己的开发效率。
假设一个场景,我们是基于接口开发工作的,接口通过JSON传递数据给前端。此时我们先定义一个JSON的结构。
public class ResponseEntity<T> implements Entity<T>,Serializable{ private static final long serialVersionUID = 1L; //数据实体 private T data; //结果码 private Integer code; //错误描述 private String message; //………… }
自定义一个异常类
public class GlobException extends RuntimeException{ private static final long serialVersionUID = 1L; private String message; private Integer code; }
定义自己的前置条件类(断言类)
/** * 断言类 * @author cjl */ public abstract class Assert { /** * 断言对象不为空,若对象为空则报异常 * @param obj 待校验对象 * @param message 异常信息 */ public static void notNull(Object obj,String message){ if(obj == null) throw new GlobException(message); } /** * 断言对象不为空,若对象为空则报异常 * @param obj 待校验对象 */ public static void notNull(Object obj){ Assert.notNull(obj, "The Object can't null"); } /** * 断言数字不能为零,若数字为零则报异常 * @param num 待校验数字 * @param message 异常信息 */ public static void notZero(Integer num,String message){ Assert.notNull(num); if(num.intValue() == 0) throw new GlobException(message); } /** * 断言数字不能为零,若数字为零则报异常 * @param num 待校验数字 */ public static void notZero(Integer num){ Assert.notZero(num,"The number can't equals zero"); } /** * 断言字符串不能为空,若字符串为空则报异常 * @param string 待校验字符串 * @param message 异常信息 */ public static void notEmpty(String string,String message){ if(StringUtils.isEmpty(string)) throw new GlobException(message); } /** * 断言字符串不能为空,若字符串为空则报异常 * @param string 待校验字符串 */ public static void notEmpty(String string){ Assert.notEmpty(string,"The string can't empty"); } /** * 断言该布尔值为true,若为false则抛异常 * @param expression 待校验布尔值 * @param message 异常信息 */ public static void isTrue(boolean expression,String message){ if(!expression) throw new GlobException(message); } /** * 断言该布尔值为true,若为false则抛异常 * @param expression 待校验布尔值 */ public static void isTrue(boolean expression){ Assert.isTrue(expression,"The expression not true"); } }
这时候在定义一个全局异常处理类,这里使用的是Spring Mvc的@ControllerAdvice注解
** * 全局异常处理 * @author cjl */ @ControllerAdvice public class ExceptionHandlers { @SuppressWarnings("rawtypes") @ResponseBody @ExceptionHandler(GlobException.class) public ResponseEntity<?> exceptionHandler(GlobException exception){ outException(exception); return new ResponseEntity(exception); } /** * 异常输出 * @param exception */ private void outException(GlobException exception) { String content = String.format("****************系统发生异常(%s)************************", exception.getMessage()); System.out.println(content); } }
和上面的例子一样,我们现在实现一个完成登录的接口。
@RequestMapping("/login") public ResponseEntity<?> login(String userName,String password){ Assert.isTrue(!(StringUtils.isEmpty(userName)||StringUtils.isEmpty(password)),"用户名或密码不能为空"); User user = userService.queryByUserNameAndPassword(userName, password); Assert.notNull(user,"用户名或密码错误"); return ResponseEntity.success(user); }
现在我们传用户名和密码,其中账号为空:
接下来传错误的用户名和密码
正确的账号密码,完成登录