欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺析Java如何優(yōu)雅的避免那無處不在的空指針異常

 更新時間:2024年03月01日 10:56:43   作者:碼農(nóng)Academy  
在Java編程語言中,NullPointerException(簡稱NPE)是一種常見的運行時異常,本文主要來和大家講講如何優(yōu)雅的避免這些空指針異常,需要的可以參考下

在Java編程語言中,NullPointerException(簡稱NPE)是一種常見的運行時異常,當程序試圖訪問或操作一個還未初始化(即值為null)的對象引用時,Java虛擬機就會拋出NullPointerException。如果我們在日常開發(fā)中,不能很好的去規(guī)避NPE,那么可能因為數(shù)據(jù)或者其他問題就會導致線上問題。。。很煩。。。。

阿里巴巴開發(fā)手冊規(guī)約中也說明防止NPE,是程序員的基本素養(yǎng)。。。

接下來我們先談談幾種可能會出現(xiàn)空指針異常的方式。

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

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

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

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

數(shù)組為null或者數(shù)組元素為null當嘗試訪問數(shù)組中的某個索引處的元素,而該元素為null時,同樣會導致空指針異常。

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

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

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

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

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

private User getUserInfo(){  
    return null;  
}

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

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

Integer i = null;  
int num = i;

以上大概是我想到或者常遇到的一些可能會發(fā)生NPE的情況,如果還有其他情況,可以貼出來討論。

那么我們該如何避免NPE呢?

避免NPE的幾種方式

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

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

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

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

關(guān)于SpringBoot項目中捕獲自定義業(yè)務異常,統(tǒng)一異常管理,統(tǒng)一結(jié)果返回,可以參考這篇文章:SpringBoot統(tǒng)一結(jié)果返回,統(tǒng)一異常處理,大牛都這么玩

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

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

String country = Optional.ofNullable(user)  
        .map(User::getAddress)  
        .map(Address::getCountry)  
        .orElse("");

String country = Optional.ofNullable(user)  
        .map(User::getAddress)  
        .map(Address::getCountry)  
        .orElseGet(() -> defaultContry());

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

我們還可以使用orElseThrow()方法,當Optional中的對象是一個null時我們直接拋出異常:

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

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

User user = new User();
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注解通常用于標記一個方法的參數(shù)、返回值或者字段可能為null。這個注解并非Java標準庫的一部分,但在一些第三方庫(如JSR 305庫中的javax.annotation.Nullable,以及Google Guava和JetBrains的Kotlin標準庫等)中廣泛使用,并且被許多IDE和靜態(tài)分析工具支持。以便在編譯期或開發(fā)工具中提示可能的NPE風險。

@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);  
}

此時IDEA就會警告會出現(xiàn)NPE風險

借助工具掃描代碼在Java開發(fā)中,我們還可以使用以下工具掃描代碼以發(fā)現(xiàn)潛在的空指針異常風險。

IntelliJ IDEA:內(nèi)置了強大的靜態(tài)代碼分析器,能夠檢測出可能的NPE和其他代碼問題。

SonarQube / SonarLint:提供持續(xù)集成和本地IDE插件形式的靜態(tài)代碼分析,能找出潛在的空指針以及其他質(zhì)量或安全問題。Sonar可以定時掃描倉庫中的代碼,可以發(fā)現(xiàn)代碼中的一些潛在風險,可以通過一些通知例如郵件等告知代碼提交者這段代碼的風險。

FindBugs(現(xiàn)更名為SpotBugs):另一個開源的靜態(tài)分析工具,能夠發(fā)現(xiàn)潛在的bug,包括可能導致NPE的情況。

阿里巴巴Java開發(fā)規(guī)約插件: 對于Eclipse和IntelliJ IDEA都有相應的插件版本,基于阿里巴巴內(nèi)部Java編碼規(guī)范,包含了對可能出現(xiàn)NPE情況的檢測。

補充一點

在JDK 17中引入的Helpful NullPointerExceptions特性確實增強了空指針異常信息的準確性與可用性。當發(fā)生NullPointerException時,JVM現(xiàn)在能夠提供更精確的位置信息,特別是在鏈式調(diào)用場景下,它會指出導致空指針異常的具體對象引用。這有助于開發(fā)者更快地定位到代碼中的問題所在,無需通過堆棧跟蹤逐層分析來判斷哪個對象引用為null。

假如我們訪問user.getAddress().getCountry().length()時,在JDK17以前,如果發(fā)生了空指針異常,他只會打印出來發(fā)生了空指針異常,但是并沒有告知到底是user對象還是address對象還是coutnry發(fā)生了異常:

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

但是在JDK17以后,借助Helpful NullPointerExceptions特性,異常信息將更加精確,可能會類似打印這樣的信息,精確到那個值發(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)

這又多了一個升級JDK到17以上的理由。

結(jié)論

NullPointerException(NPE)是Java開發(fā)中常見的運行時異常,源于對未初始化或已置為null的對象引用進行操作。在實際開發(fā)過程中,進行非空檢查、使用Optional類以及采用Null安全注解以及使用檢查工具等策略可以有效避免此類異常的發(fā)生。

以上就是淺析Java如何優(yōu)雅的避免那無處不在的空指針異常的詳細內(nèi)容,更多關(guān)于Java如何避免空指針異常的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解IDEA社區(qū)版(Community)和付費版(UItimate)的區(qū)別

    詳解IDEA社區(qū)版(Community)和付費版(UItimate)的區(qū)別

    這篇文章主要介紹了詳解IDEA社區(qū)版(Community)和付費版(UItimate)的區(qū)別,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • SpringBoot實現(xiàn)線程池

    SpringBoot實現(xiàn)線程池

    現(xiàn)在由于系統(tǒng)越來越復雜,導致很多接口速度變慢,這時候就會想到可以利用線程池來處理一些耗時并不影響系統(tǒng)的操作。本文就介紹了SpringBoot線程池的使用,感興趣的可以了解一下
    2021-06-06
  • SpringBoot使用RabbitMQ延時隊列(小白必備)

    SpringBoot使用RabbitMQ延時隊列(小白必備)

    這篇文章主要介紹了SpringBoot使用RabbitMQ延時隊列(小白必備),詳細的介紹延遲隊列的使用場景及其如何使用,需要的小伙伴可以一起來了解一下
    2019-12-12
  • Spring Boot配置Thymeleaf(gradle)的簡單使用

    Spring Boot配置Thymeleaf(gradle)的簡單使用

    今天小編就為大家分享一篇關(guān)于Spring Boot配置Thymeleaf(gradle)的簡單使用,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Java中數(shù)據(jù)轉(zhuǎn)換及字符串的“+”操作方法

    Java中數(shù)據(jù)轉(zhuǎn)換及字符串的“+”操作方法

    本文主要介紹了Java中的數(shù)據(jù)類型轉(zhuǎn)換,包括隱式轉(zhuǎn)換和強制轉(zhuǎn)換,隱式轉(zhuǎn)換通常用于將范圍較小的數(shù)據(jù)類型轉(zhuǎn)換為范圍較大的數(shù)據(jù)類型,而強制轉(zhuǎn)換則是將范圍較大的數(shù)據(jù)類型轉(zhuǎn)換為范圍較小的數(shù)據(jù)類型,本文介紹Java中數(shù)據(jù)轉(zhuǎn)換以及字符串的“+”操作,感興趣的朋友一起看看吧
    2024-10-10
  • MyBatis中SQL片段復用使用方法詳解

    MyBatis中SQL片段復用使用方法詳解

    在使用 MyBatis 進行數(shù)據(jù)庫操作時,常常會遇到一些 SQL 語句的部分內(nèi)容重復出現(xiàn)的情況,比如多個查詢語句都涉及相同的字段列表,這時,MyBatis 的 SQL 片段復用功能就派上用場了,接下小編給大家介紹了MyBatis中SQL片段復用使用方法,需要的朋友可以參考下
    2024-12-12
  • 你知道Java中的注解可以繼承嗎?

    你知道Java中的注解可以繼承嗎?

    注解想必大家都用過,也叫元數(shù)據(jù),是一種代碼級別的注釋,可以對類或者方法等元素做標記說明。那么今天我想問大家的是類被繼承了,注解能否繼承呢?可能會和大家想的不一樣,感興趣的可以往下看
    2022-12-12
  • 淺談java線程join方法使用方法

    淺談java線程join方法使用方法

    這篇文章主要介紹了淺談java線程join方法使用方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-09-09
  • SpringBoot @PostConstruct原理用法解析

    SpringBoot @PostConstruct原理用法解析

    這篇文章主要介紹了SpringBoot @PostConstruct原理用法解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-08-08
  • Spring Boot修改內(nèi)置Tomcat默認端口號的示例

    Spring Boot修改內(nèi)置Tomcat默認端口號的示例

    本篇文章主要介紹了Spring Boot修改內(nèi)置Tomcat端口號的示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08

最新評論