最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java如何優(yōu)雅地避免空指針異常(NullPointerException)

 更新時(shí)間:2024年03月12日 08:33:25   作者:編程小猹  
這篇文章主要給大家介紹了關(guān)于Java如何優(yōu)雅地避免空指針異常(NullPointerException)的相關(guān)資料,空指針異常(NullPointerException)是一種常見的運(yùn)行時(shí)異常,它在Java編程中經(jīng)常出現(xiàn),需要的朋友可以參考下

前言

空指針異常是導(dǎo)致java程序運(yùn)行中斷最常見的原因,相信每個(gè)程序猿都碰見過,也就是NullPointException,我們通常簡稱為NPE,為了提高我們寫的代碼的健壯性,本文告訴大家如何優(yōu)雅避免NPE。

出現(xiàn)空指針異常的情況

訪問空對(duì)象的屬性或調(diào)用空對(duì)象的方法

當(dāng)一個(gè)對(duì)象是null時(shí),試圖訪問一個(gè)對(duì)象的屬性或調(diào)用其方法,就會(huì)觸發(fā)空指針異常。

代碼示例

String text = null;
int length = text.length();

User user = null;
String userName = user.getUserName();

數(shù)組為null或者數(shù)組元素為null

當(dāng)嘗試訪問數(shù)組中的某個(gè)索引處的元素,而該元素為null時(shí),同樣會(huì)導(dǎo)致空指針異常。

String[] strs = null;
int length = strs.length;

String[] strs = new String[3];  
int length = strs[2].length();

集合中null元素訪問

當(dāng)集合中存在null元素,當(dāng)我們遍歷集合,訪問到這個(gè)元素的屬性或者方法時(shí)也會(huì)拋出NPE,這種情況也會(huì)出現(xiàn)在我們的日常開發(fā)中,有時(shí)候就會(huì)因?yàn)閿?shù)據(jù)問題導(dǎo)致這種情況發(fā)生,常常也莫名其妙。。。。

List<String> list = Lists.newArrayList();  
list.add(null);  
System.out.println(list.get(0).length());

調(diào)用的方法返回null

調(diào)用某個(gè)方法,期望其返回一個(gè)非null的對(duì)象,但實(shí)際返回了null。當(dāng)然這種情況等同于訪問空對(duì)象的屬性或者方法。這在實(shí)際開發(fā)過程中極易出現(xiàn)的一種情況。比如我們使用Mybatis從數(shù)據(jù)庫中查詢一條記錄時(shí),數(shù)據(jù)不存在,就會(huì)返回null。這種情況尤為注意。

使用基本數(shù)據(jù)類型的包裝類

在使用基本數(shù)據(jù)類型的包裝類時(shí),如果未正確初始化,再轉(zhuǎn)成int時(shí),可能導(dǎo)致空指針異常。

Integer i = null;  
int num = i;

避免NPE的幾種方式

訪問對(duì)象前要謹(jǐn)慎

在使用對(duì)象之前,始終檢查它是否為null。這包括方法參數(shù)、返回值以及對(duì)象的屬性。在訪問對(duì)象的方法或?qū)傩灾?,使用條件語句判斷對(duì)象是否為null。比如我們?cè)谠L問User對(duì)象前,一定要判null。

如果對(duì)象訪問不可避免時(shí),我們也要遵循以下規(guī)則:

在使用對(duì)象之前,始終檢查它是否為null

包括方法參數(shù)、返回值以及對(duì)象的屬性。在訪問對(duì)象的方法或?qū)傩灾?,使用條件語句判斷對(duì)象是否為null。比如我們?cè)谠L問User對(duì)象前,一定要判null。

User user = new User();  
if (user != null){  
    String userName = user.getUserName();  
    Address address = user.getAddress();  
    if (address != null){  
        String coutry = address.getCountry();  
    }  
}

或者我們的user是從一個(gè)方法中獲取的,例如數(shù)據(jù)庫中查詢,那么我們?cè)谠L問這個(gè)對(duì)象前,一定要判null,如果為null要拋出對(duì)應(yīng)的業(yè)務(wù)異常,然后我們就可以在接口響應(yīng)中對(duì)應(yīng)返回錯(cuò)誤的信息即可,此時(shí)就算是一個(gè)正常的流程了。這點(diǎn)尤為重要,一定要注意。

User user = userManager.getUserById(Long userId);
if (user == null){
	throw new ServiceException(""當(dāng)前查詢的對(duì)象不存在);
}

當(dāng)然如果使我們?cè)趯?code>User getUserById(Long id)返回對(duì)象或者List<User> listUserByIds(List<Long> idList)時(shí)我們可以不返回null,可以返回一個(gè)對(duì)象默認(rèn)信息或者一個(gè)空集合,這樣調(diào)用方就不會(huì)出現(xiàn)NPE風(fēng)險(xiǎn),當(dāng)然我們不強(qiáng)制返回一個(gè)對(duì)象或者空集合,但是必須添加注釋充分 說明什么情況下會(huì)返回null值。這也是阿里巴巴開發(fā)手冊(cè)規(guī)約的建議。

 從已知的String對(duì)象中調(diào)用equals()和equalsIgnoreCase()方法,而非未知對(duì)象。

總是從已知的非空String對(duì)象中調(diào)用equals()方法。因?yàn)閑quals()方法是對(duì)稱的,調(diào)用a.equals(b)和調(diào)用b.equals(a)是完全相同的,這也是為什么程序員對(duì)于對(duì)象a和b這么不上心。如果調(diào)用者是空指針,這種調(diào)用可能導(dǎo)致一個(gè)空指針異常

Object unknownObject = null ;
 
//錯(cuò)誤方式 – 可能導(dǎo)致 NullPointerException
if (unknownObject.equals( "knownObject" )){
   System.err.println( "This may result in NullPointerException if unknownObject is null" );
}
 
//正確方式 - 即便 unknownObject是null也能避免NullPointerException
if ( "knownObject" .equals(unknownObject)){
   System.err.println( "better coding avoided NullPointerException" );
}

 當(dāng)valueOf()和toString()返回相同的結(jié)果時(shí),寧愿使用前者。

因?yàn)檎{(diào)用null對(duì)象的toString()會(huì)拋出空指針異常,如果我們能夠使用valueOf()獲得相同的值,那寧愿使用valueOf(),傳遞一個(gè)null給valueOf()將會(huì)返回“null”,尤其是在那些包裝類,像Integer、Float、Double和BigDecimal。

BigDecimal bd = getPrice();
System.out.println(String.valueOf(bd)); //不會(huì)拋出空指針異常
System.out.println(bd.toString()); //拋出 "Exception in thread "main"

使用Optional類

JDK8以上版本提供了Optional類,它是一個(gè)容器對(duì)象,可用于包裝可能為null的值。我們可以使用它判斷null問題,同時(shí)也解決了多層級(jí)訪問問題,配合使用orElse時(shí),會(huì)先執(zhí)行orElse方法,然后執(zhí)行邏輯代碼,不管是否出現(xiàn)了空指針。

//獲取user對(duì)象中的Country屬性,如果為空則會(huì)存儲(chǔ)一個(gè)空字符串到country中
String country = Optional.ofNullable(user)  
        .map(User::getAddress)  
        .map(Address::getCountry)  
        .orElse("");
//獲取user對(duì)象中的Country屬性,如果Country屬性為空則會(huì)存儲(chǔ)一個(gè)空字符串到country中
String country = Optional.ofNullable(user)  
        .map(User::getAddress)  
        .map(Address::getCountry)  
        .orElseGet(() -> defaultContry());

private String defaultContry(){
	return "CN";
}

我們還可以使用orElseThrow()方法,當(dāng)Optional中的對(duì)象是一個(gè)null時(shí)我們直接拋出異常:

String userName = Optional
.ofNullable(user)
.map(User::getUserName)
.orElseThrow(() -> new ServiceException("當(dāng)前用戶信息不存在"));

定義數(shù)據(jù)庫中的字段是否可為空。

如果你在使用數(shù)據(jù)庫來保存你的域名對(duì)象,如Customers,Orders 等,你需要在數(shù)據(jù)庫本身定義是否為空的約束。因?yàn)閿?shù)據(jù)庫會(huì)從很多代碼中獲取數(shù)據(jù),數(shù)據(jù)庫中有是否為空的檢查可以確保你的數(shù)據(jù)健全。在數(shù)據(jù)空中維護(hù)null約束同樣可以幫助你減少Java代碼中的空指針檢查。當(dāng)從數(shù)據(jù)庫中加載一個(gè)對(duì)象是你會(huì)明確,哪些字段是可以為null的,而哪些不能,這可以使你代碼中不必要的!= null檢查最少化。

使用斷言避免空指針

使用Java斷言(assert)來檢查變量是否為null。但要注意,斷言通常在開發(fā)和測試階段啟用,而在生產(chǎn)環(huán)境中可能被禁用(在生產(chǎn)環(huán)境中,通常不會(huì)啟用斷言以避免不必要的性能開銷以及防止?jié)撛诘腻e(cuò)誤信息泄漏)。

User user = new User();
//使用斷言確保 user 對(duì)象不為 null。如果 user 為 null,則會(huì)拋出 AssertionError,
//并顯示消息 "user should not be null"。
assert user != null : "user should not be null";
Address address = user.getAddress();  
assert address != null : "address should not be null";  
String coutry = address.getCountry();

使用@Nullable注解

使用javax.annotation.Nullable注解,@Nullable注解通常用于標(biāo)記一個(gè)方法的參數(shù)、返回值或者字段可能為null。這個(gè)注解并非Java標(biāo)準(zhǔn)庫的一部分,但在一些第三方庫(如JSR 305庫中的javax.annotation.Nullable,以及Google Guava和JetBrains的Kotlin標(biāo)準(zhǔn)庫等)中廣泛使用,并且被許多IDE和靜態(tài)分析工具支持。以便在編譯期或開發(fā)工具中提示可能的NPE風(fēng)險(xiǎn)。

@Nullable  
private static User getUserById(Long userId){  
    return null;  
}  
  
private static void handlerUser(@Nullable User user){  
    System.out.println(user.getUserName());  
}

public static void main(String[] args) {  
  Long userId = 0L;  
  User user = getUserById(userId);  
  String userName = user.getUserName();  
  handlerUser(user);  
}

此時(shí)IDEA就會(huì)警告會(huì)出現(xiàn)NPE風(fēng)險(xiǎn)

避免從方法中返回空指針,而是返回空collection或者空數(shù)組。

這個(gè)Java最佳實(shí)踐或技巧由Joshua Bloch在他的書Effective Java中提到。這是另外一個(gè)可以更好的使用Java編程的技巧。通過返回一個(gè)空collection或者空數(shù)組,你可以確保在調(diào)用如size(),length()的時(shí)候不會(huì)因?yàn)榭罩羔槷惓1罎?。Collections類提供了方便的空List,Set和Map: Collections.EMPTY_LIST,Collections.EMPTY_SET,Collections.EMPTY_MAP。這里是實(shí)例。

public List getOrders(Customer customer){
   List result = Collections.EMPTY_LIST;
   return result;
}

使用null安全的方法和庫 有很多開源庫已經(jīng)為您做了繁重的空指針檢查工作。

其中最常用的一個(gè)的是Apache commons 中的StringUtils。你可以使用StringUtils.isBlank(),isNumeric(),isWhiteSpace()以及其他的工具方法而不用擔(dān)心空指針異常。

//StringUtils方法是空指針安全的,他們不會(huì)拋出空指針異常
System.out.println(StringUtils.isEmpty( null ));
System.out.println(StringUtils.isBlank( null ));
System.out.println(StringUtils.isNumeric( null ));
System.out.println(StringUtils.isAllUpperCase( null ));
 
Output:
true
true
false
false

補(bǔ)充

在JDK 17中引入的Helpful NullPointerExceptions特性確實(shí)增強(qiáng)了空指針異常信息的準(zhǔn)確性與可用性。當(dāng)發(fā)生NullPointerException時(shí),JVM現(xiàn)在能夠提供更精確的位置信息,特別是在鏈?zhǔn)秸{(diào)用場景下,它會(huì)指出導(dǎo)致空指針異常的具體對(duì)象引用。這有助于開發(fā)者更快地定位到代碼中的問題所在,無需通過堆棧跟蹤逐層分析來判斷哪個(gè)對(duì)象引用為null。假如我們?cè)L問user.getAddress().getCountry().length()時(shí),在JDK17以前,如果發(fā)生了空指針異常,他只會(huì)打印出來發(fā)生了空指針異常,但是并沒有告知到底是user對(duì)象還是address對(duì)象還是coutnry發(fā)生了異常:

Exception in thread "main" java.lang.NullPointerException
	at com.study.base.core.base.NpeTest.main(NpeTest.java:23)

但是在JDK17以后,借助Helpful NullPointerExceptions特性,異常信息將更加精確,可能會(huì)類似打印這樣的信息,精確到哪個(gè)值發(fā)生了空指針異常:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Address.getCountry()" because "user.address" is null
	at com.study.base.core.base.NpeTest.main(NpeTest.java:23)

總結(jié)

到此這篇關(guān)于Java如何優(yōu)雅地避免空指針異常(NullPointerException)的文章就介紹到這了,更多相關(guān)Java避免空指針異常內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java面試題沖刺第二十四天--并發(fā)編程

    Java面試題沖刺第二十四天--并發(fā)編程

    這篇文章主要為大家分享了最有價(jià)值的三道關(guān)于數(shù)據(jù)庫的面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Spring AOP 支持哪兩種動(dòng)態(tài)代理方式(最新推薦)

    Spring AOP 支持哪兩種動(dòng)態(tài)代理方式(最新推薦)

    動(dòng)態(tài)代理在運(yùn)行時(shí)創(chuàng)建目標(biāo)對(duì)象的增強(qiáng)代理,Spring AOP支持JDK代理(基于接口)和CGLIB代理(基于繼承),Spring Boot默認(rèn)使用CGLIB解決方法自調(diào)用問題,也可通過配置切換代理方式,本文給大家介紹Spring AOP支持哪兩種動(dòng)態(tài)代理方式,感興趣的朋友一起看看吧
    2025-06-06
  • 一篇文章弄懂Mybatis中#和$的區(qū)別

    一篇文章弄懂Mybatis中#和$的區(qū)別

    mybatis為我們提供了兩種支持動(dòng)態(tài)sql的語法#{}以及${},兩者都是動(dòng)態(tài)的向sql語句中傳入需要的參數(shù),下面這篇文章主要給大家介紹了如何通過一篇文章弄懂Mybatis中#和$區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2021-12-12
  • Java中的自旋鎖與適應(yīng)性自旋鎖的區(qū)別

    Java中的自旋鎖與適應(yīng)性自旋鎖的區(qū)別

    這篇文章主要介紹了Java中的自旋鎖與適應(yīng)性自旋鎖的區(qū)別,當(dāng)一個(gè)線程嘗試去獲取某一把鎖的時(shí)候,如果這個(gè)鎖此時(shí)已經(jīng)被別人獲取(占用),那么此線程就無法獲取到這把鎖,該線程將會(huì)等待,間隔一段時(shí)間后會(huì)再次嘗試獲取,需要的朋友可以參考下
    2023-10-10
  • 使用VS?Code進(jìn)行java開發(fā)與調(diào)試的圖文教程

    使用VS?Code進(jìn)行java開發(fā)與調(diào)試的圖文教程

    這篇文章主要介紹了如何在計(jì)算機(jī)上安裝JDK、VSCode以及Java擴(kuò)展包,并詳細(xì)說明了配置Java運(yùn)行環(huán)境的過程,還展示了如何在VSCode中新建一個(gè)Java項(xiàng)目,需要的朋友可以參考下
    2025-02-02
  • 基于JDK動(dòng)態(tài)代理原理解析

    基于JDK動(dòng)態(tài)代理原理解析

    這篇文章主要介紹了基于JDK動(dòng)態(tài)代理原理解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • 詳解Java的Hibernate框架中的set映射集與SortedSet映射

    詳解Java的Hibernate框架中的set映射集與SortedSet映射

    這篇文章主要介紹了詳解Java的Hibernate框架中的set映射集與SortedSet映射,Hibernate是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下
    2015-12-12
  • Java 同步關(guān)鍵字 synchronized用法 、場景及避坑指南

    Java 同步關(guān)鍵字 synchronized用法 、場景及避坑指南

    synchronized 是 Java 最基礎(chǔ)、最常用的線程同步方式,優(yōu)點(diǎn)是 簡單易用、無需手動(dòng)釋放鎖、JVM 自動(dòng)優(yōu)化,適合解決大多數(shù)線程安全問題,本文給大家介紹Java 同步關(guān)鍵字 synchronized用法 + 場景 + 避坑指南,感興趣的朋友跟隨小編一起看看吧
    2025-12-12
  • Spring Boot+Nginx實(shí)現(xiàn)大文件下載功能

    Spring Boot+Nginx實(shí)現(xiàn)大文件下載功能

    相信很多小伙伴,在日常開放中都會(huì)遇到大文件下載的情況,大文件下載方式也有很多,比如非常流行的分片下載、斷點(diǎn)下載;當(dāng)然也可以結(jié)合Nginx來實(shí)現(xiàn)大文件下載,在中小項(xiàng)目非常適合使用,這篇文章主要介紹了Spring Boot結(jié)合Nginx實(shí)現(xiàn)大文件下載,需要的朋友可以參考下
    2024-05-05
  • Java內(nèi)存模型的深入講解

    Java內(nèi)存模型的深入講解

    這篇文章主要給大家介紹了關(guān)于Java內(nèi)存模型的相關(guān)資料,我們常說的JVM內(nèi)存模式指的是JVM的內(nèi)存分區(qū),而Java內(nèi)存模式是一種虛擬機(jī)規(guī)范,需要的朋友可以參考下
    2021-07-07

最新評(píng)論

外汇| 黄大仙区| 城固县| 方城县| 磐安县| 利川市| 广元市| 沂源县| 凌源市| 尼勒克县| 呼图壁县| 枝江市| 静宁县| 武夷山市| 浮山县| 隆昌县| 凤城市| 灵川县| 息烽县| 瓮安县| 庄河市| 大石桥市| 中山市| 湖北省| 沅江市| 会东县| 会同县| 贵溪市| 邯郸县| 天祝| 曲阳县| 庆阳市| 广南县| 淮南市| 应城市| 苏尼特右旗| 陆河县| 来宾市| 梨树县| 武陟县| 甘谷县|