運行下面代碼,會拋出NPE。你知道爲什麼嗎?
import cn.hutool.core.lang.Assert; public class TestMain { public static void main(String[] args) { MyClass myClass = new MyClass(); Assert.isTrue(myClass.myProperty == 0); } private static class MyClass { private Integer myProperty; } }
原因:初始化myClass對象後,Integer類型的myProperty屬性的值是默認值null。此時,執行myClass.myProperty == 0,其實是調用了 Integer#intValue()方法進行拆箱操作,由於Integer對象是null,致使NPE。
上面代碼在IDE裏不會提示任何問題。而下面代碼,IDE則會給出NPE提示。
我今天在寫一個對外暴露的接口方法,利用斷言判斷入參合法性時,恰好想到了這個問題點。就像上面的示例代碼,還沒到執行斷言呢,就拋出了NPE了。顯然,要先斷言屬性不爲null。
如下是我改完後的程序代碼
public Result<UserSignDTO> userHasSign(UserSignQuery userSignQuery) { try { Assert.notNull(userSignQuery); Assert.notNull(userSignQuery.getIdcardNo()); Assert.notNull(userSignQuery.getEnterpriseId()); Assert.notNull(userSignQuery.getProviderId()); Assert.isTrue(userSignQuery.getEnterpriseId()>0); Assert.isTrue(userSignQuery.getProviderId()>0); ... } catch (IllegalArgumentException e) { return Result.err(e.getMessage()); } }
毋庸置疑,用斷言可以增加代碼的優雅度。而這一坨Assert,卻跟優雅沾不上邊。
於是乎,發揮點匠心精神吧。下面AssertUtil問世,基於Assert進行工具的封裝。
package com.emax.common.util; import cn.hutool.core.lang.Assert; public class AssertUtil { /** * 斷言所有對象是否不爲{@code null} ,如果爲{@code null} 拋出{@link IllegalArgumentException} 異常 * * @param errMsg 斷言失敗的錯誤消息 * @param objects */ @SafeVarargs public static <T> void allNotNull(String errMsg, T... objects) throws IllegalArgumentException { for (T object : objects) { T t = errMsg == null ? Assert.notNull(object) : Assert.notNull(object, errMsg); } } /** * 斷言所有對象是否不爲{@code null} ,如果爲{@code null} 拋出{@link IllegalArgumentException} 異常 * * @param objects */ public static <T> void allNotNull(T... objects) throws IllegalArgumentException { allNotNull(null, objects); } /** * 判斷對象是數字,並且大於0 * * @param number * @throws IllegalArgumentException */ public static void gt0(Number number) throws IllegalArgumentException { Assert.notNull(number); Assert.isTrue(number.longValue() > 0); } ....其他斷言方法 }
OK,改爲使用AssertUtil斷言,如下,是不是優雅?你品。
public Result<UserSignDTO> userHasSign(UserSignQuery userSignQuery) { try { AssertUtil.allNotNull(userSignQuery, userSignQuery.getIdCardNo()); AssertUtil.gt0(userSignQuery.getEnterpriseId()); AssertUtil.gt0(userSignQuery.getProviderId()); if (userSignQuery.getUserId() == 0 || StringUtils.isBlank(userSignQuery.getIdcardNo())) { throw new IllegalArgumentException("userId或身份證號碼必傳一項"); } ... } catch (IllegalArgumentException e) { return Result.err(e.getMessage()); } }