'高級工程師系列之在Java中如何優雅地判空'

Java 程序設計 維基百科 前端學習愛好者 2019-08-23
"

判空災難

"

判空災難

高級工程師系列之在Java中如何優雅地判空

NullPointerException

作為搬磚黨的一族們,我們對判空一定再熟悉不過了,不要跟我說你很少進行判空,除非你喜歡NullPointerException。

不過NullPointerException對於很多猿們來說,也是Exception家族中最親近的一員了。

"

判空災難

高級工程師系列之在Java中如何優雅地判空

NullPointerException

作為搬磚黨的一族們,我們對判空一定再熟悉不過了,不要跟我說你很少進行判空,除非你喜歡NullPointerException。

不過NullPointerException對於很多猿們來說,也是Exception家族中最親近的一員了。

高級工程師系列之在Java中如何優雅地判空

Wowo

為了避免NullPointerException來找我們,我們經常會進行如下操作。

if (data != null) {
do sth.
}

如果一個類中多次使用某個對象,那你可能要一頓操作,so:

"

判空災難

高級工程師系列之在Java中如何優雅地判空

NullPointerException

作為搬磚黨的一族們,我們對判空一定再熟悉不過了,不要跟我說你很少進行判空,除非你喜歡NullPointerException。

不過NullPointerException對於很多猿們來說,也是Exception家族中最親近的一員了。

高級工程師系列之在Java中如何優雅地判空

Wowo

為了避免NullPointerException來找我們,我們經常會進行如下操作。

if (data != null) {
do sth.
}

如果一個類中多次使用某個對象,那你可能要一頓操作,so:

高級工程師系列之在Java中如何優雅地判空

1

“世界第九大奇蹟”就這樣誕生了。Maybe你會想,項目中肯定不止你一個人會這樣一頓操作,然後按下Command+Shift+F,真相就在眼前:

"

判空災難

高級工程師系列之在Java中如何優雅地判空

NullPointerException

作為搬磚黨的一族們,我們對判空一定再熟悉不過了,不要跟我說你很少進行判空,除非你喜歡NullPointerException。

不過NullPointerException對於很多猿們來說,也是Exception家族中最親近的一員了。

高級工程師系列之在Java中如何優雅地判空

Wowo

為了避免NullPointerException來找我們,我們經常會進行如下操作。

if (data != null) {
do sth.
}

如果一個類中多次使用某個對象,那你可能要一頓操作,so:

高級工程師系列之在Java中如何優雅地判空

1

“世界第九大奇蹟”就這樣誕生了。Maybe你會想,項目中肯定不止你一個人會這樣一頓操作,然後按下Command+Shift+F,真相就在眼前:

高級工程師系列之在Java中如何優雅地判空

2

What,我們有接近一萬行的代碼都是在判空?

"

判空災難

高級工程師系列之在Java中如何優雅地判空

NullPointerException

作為搬磚黨的一族們,我們對判空一定再熟悉不過了,不要跟我說你很少進行判空,除非你喜歡NullPointerException。

不過NullPointerException對於很多猿們來說,也是Exception家族中最親近的一員了。

高級工程師系列之在Java中如何優雅地判空

Wowo

為了避免NullPointerException來找我們,我們經常會進行如下操作。

if (data != null) {
do sth.
}

如果一個類中多次使用某個對象,那你可能要一頓操作,so:

高級工程師系列之在Java中如何優雅地判空

1

“世界第九大奇蹟”就這樣誕生了。Maybe你會想,項目中肯定不止你一個人會這樣一頓操作,然後按下Command+Shift+F,真相就在眼前:

高級工程師系列之在Java中如何優雅地判空

2

What,我們有接近一萬行的代碼都是在判空?

高級工程師系列之在Java中如何優雅地判空

3

好了,接下來,要進入正題了。

NullObject模式

對於項目中無數次的判空,對代碼質量整潔度產生了十分之惡劣的影響,對於這種現象,我們稱之為“判空災難”。

那麼,這種現象如何治理呢,你可能聽說過NullObject模式,不過這不是我們今天的武器,但是還是需要介紹一下NullObject模式。

什麼是NullObject模式呢?

In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral ("null") behavior. The null object design pattern describes the uses of such objects and their behavior (or lack thereof).

以上解析來自Wikipedia。

NullObject模式首次發表在“ 程序設計模式語言 ”系列叢書中。一般的,在面嚮對象語言中,對對象的調用前需要使用判空檢查,來判斷這些對象是否為空,因為在空引用上無法調用所需方法。

空對象模式的一種典型實現方式如下圖所示(圖片來自網絡):

"

判空災難

高級工程師系列之在Java中如何優雅地判空

NullPointerException

作為搬磚黨的一族們,我們對判空一定再熟悉不過了,不要跟我說你很少進行判空,除非你喜歡NullPointerException。

不過NullPointerException對於很多猿們來說,也是Exception家族中最親近的一員了。

高級工程師系列之在Java中如何優雅地判空

Wowo

為了避免NullPointerException來找我們,我們經常會進行如下操作。

if (data != null) {
do sth.
}

如果一個類中多次使用某個對象,那你可能要一頓操作,so:

高級工程師系列之在Java中如何優雅地判空

1

“世界第九大奇蹟”就這樣誕生了。Maybe你會想,項目中肯定不止你一個人會這樣一頓操作,然後按下Command+Shift+F,真相就在眼前:

高級工程師系列之在Java中如何優雅地判空

2

What,我們有接近一萬行的代碼都是在判空?

高級工程師系列之在Java中如何優雅地判空

3

好了,接下來,要進入正題了。

NullObject模式

對於項目中無數次的判空,對代碼質量整潔度產生了十分之惡劣的影響,對於這種現象,我們稱之為“判空災難”。

那麼,這種現象如何治理呢,你可能聽說過NullObject模式,不過這不是我們今天的武器,但是還是需要介紹一下NullObject模式。

什麼是NullObject模式呢?

In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral ("null") behavior. The null object design pattern describes the uses of such objects and their behavior (or lack thereof).

以上解析來自Wikipedia。

NullObject模式首次發表在“ 程序設計模式語言 ”系列叢書中。一般的,在面嚮對象語言中,對對象的調用前需要使用判空檢查,來判斷這些對象是否為空,因為在空引用上無法調用所需方法。

空對象模式的一種典型實現方式如下圖所示(圖片來自網絡):

高級工程師系列之在Java中如何優雅地判空

4

示例代碼如下(命名來自網絡,哈哈到底是有多懶):

Nullable是空對象的相關操作接口,用於確定對象是否為空,因為在空對象模式中,對象為空會被包裝成一個Object,成為Null Object,該對象會對原有對象的所有方法進行空實現。。

public interface Nullable {

boolean isNull();

}

這個接口定義了業務對象的行為。

public interface DependencyBase extends Nullable {
void Operation();
}

這是該對象的真實類,實現了業務行為接口DependencyBase與空對象操作接口Nullable。

public class Dependency implements DependencyBase, Nullable {
@Override
public void Operation() {
System.out.print("Test!");
}
@Override
public boolean isNull() {
return false;
}

}

這是空對象,對原有對象的行為進行了空實現。

public class NullObject implements DependencyBase{
@Override
public void Operation() {
// do nothing
}
@Override
public boolean isNull() {
return true;
}

}

在使用時,可以通過工廠調用方式來進行空對象的調用,也可以通過其他如反射的方式對對象進行調用(一般多耗時幾毫秒)在此不進行詳細敘述。

public class Factory {

public static DependencyBase get(Nullable dependencyBase){
if (dependencyBase == null){
return new NullObject();
}
return new Dependency();
}

}

這是一個使用範例,通過這種模式,我們不再需要進行對象的判空操作,而是可以直接使用對象,也不必擔心NPE(NullPointerException)的問題。

public class Client {
public void test(DependencyBase dependencyBase){
Factory.get(dependencyBase).Operation();
}
}

關於空對象模式,更具體的內容大家也可以多找一找資料,上述只是對NullObject的簡單介紹,但是,今天我要推薦的是一款協助判空的插件NR Null Object,讓我們來優雅地進行判空,不再進行一頓操作來定義繁瑣的空對象接口與空獨享實現類。

.NR Null Object

NR Null Object是一款適用於Android Studio、IntelliJ IDEA、PhpStorm、WebStorm、PyCharm、RubyMine、AppCode、CLion、GoLand、DataGrip等IDEA的Intellij插件。其可以根據現有對象,便捷快速生成其空對象模式需要的組成成分,其包含功能如下:

  • 分析所選類可聲明為接口的方法;
  • 抽象出公有接口;
  • 創建空對象,自動實現公有接口;
  • 對部分函數進行可為空聲明;
  • 可追加函數進行再次生成;
  • 自動的函數命名規範

讓我們來看一個使用範例:

"

判空災難

高級工程師系列之在Java中如何優雅地判空

NullPointerException

作為搬磚黨的一族們,我們對判空一定再熟悉不過了,不要跟我說你很少進行判空,除非你喜歡NullPointerException。

不過NullPointerException對於很多猿們來說,也是Exception家族中最親近的一員了。

高級工程師系列之在Java中如何優雅地判空

Wowo

為了避免NullPointerException來找我們,我們經常會進行如下操作。

if (data != null) {
do sth.
}

如果一個類中多次使用某個對象,那你可能要一頓操作,so:

高級工程師系列之在Java中如何優雅地判空

1

“世界第九大奇蹟”就這樣誕生了。Maybe你會想,項目中肯定不止你一個人會這樣一頓操作,然後按下Command+Shift+F,真相就在眼前:

高級工程師系列之在Java中如何優雅地判空

2

What,我們有接近一萬行的代碼都是在判空?

高級工程師系列之在Java中如何優雅地判空

3

好了,接下來,要進入正題了。

NullObject模式

對於項目中無數次的判空,對代碼質量整潔度產生了十分之惡劣的影響,對於這種現象,我們稱之為“判空災難”。

那麼,這種現象如何治理呢,你可能聽說過NullObject模式,不過這不是我們今天的武器,但是還是需要介紹一下NullObject模式。

什麼是NullObject模式呢?

In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral ("null") behavior. The null object design pattern describes the uses of such objects and their behavior (or lack thereof).

以上解析來自Wikipedia。

NullObject模式首次發表在“ 程序設計模式語言 ”系列叢書中。一般的,在面嚮對象語言中,對對象的調用前需要使用判空檢查,來判斷這些對象是否為空,因為在空引用上無法調用所需方法。

空對象模式的一種典型實現方式如下圖所示(圖片來自網絡):

高級工程師系列之在Java中如何優雅地判空

4

示例代碼如下(命名來自網絡,哈哈到底是有多懶):

Nullable是空對象的相關操作接口,用於確定對象是否為空,因為在空對象模式中,對象為空會被包裝成一個Object,成為Null Object,該對象會對原有對象的所有方法進行空實現。。

public interface Nullable {

boolean isNull();

}

這個接口定義了業務對象的行為。

public interface DependencyBase extends Nullable {
void Operation();
}

這是該對象的真實類,實現了業務行為接口DependencyBase與空對象操作接口Nullable。

public class Dependency implements DependencyBase, Nullable {
@Override
public void Operation() {
System.out.print("Test!");
}
@Override
public boolean isNull() {
return false;
}

}

這是空對象,對原有對象的行為進行了空實現。

public class NullObject implements DependencyBase{
@Override
public void Operation() {
// do nothing
}
@Override
public boolean isNull() {
return true;
}

}

在使用時,可以通過工廠調用方式來進行空對象的調用,也可以通過其他如反射的方式對對象進行調用(一般多耗時幾毫秒)在此不進行詳細敘述。

public class Factory {

public static DependencyBase get(Nullable dependencyBase){
if (dependencyBase == null){
return new NullObject();
}
return new Dependency();
}

}

這是一個使用範例,通過這種模式,我們不再需要進行對象的判空操作,而是可以直接使用對象,也不必擔心NPE(NullPointerException)的問題。

public class Client {
public void test(DependencyBase dependencyBase){
Factory.get(dependencyBase).Operation();
}
}

關於空對象模式,更具體的內容大家也可以多找一找資料,上述只是對NullObject的簡單介紹,但是,今天我要推薦的是一款協助判空的插件NR Null Object,讓我們來優雅地進行判空,不再進行一頓操作來定義繁瑣的空對象接口與空獨享實現類。

.NR Null Object

NR Null Object是一款適用於Android Studio、IntelliJ IDEA、PhpStorm、WebStorm、PyCharm、RubyMine、AppCode、CLion、GoLand、DataGrip等IDEA的Intellij插件。其可以根據現有對象,便捷快速生成其空對象模式需要的組成成分,其包含功能如下:

  • 分析所選類可聲明為接口的方法;
  • 抽象出公有接口;
  • 創建空對象,自動實現公有接口;
  • 對部分函數進行可為空聲明;
  • 可追加函數進行再次生成;
  • 自動的函數命名規範

讓我們來看一個使用範例:

高級工程師系列之在Java中如何優雅地判空

5

怎麼樣,看起來是不是非常快速便捷,只需要在原有需要進行多次判空的對象中,郵件彈出菜單,選擇Generate,並選擇NR Null Object即可自動生成相應的空對象組件。

那麼如何來獲得這款插件呢?

安裝方式

可以直接通過IDEA的Preferences中的Plugins倉庫進行安裝。

選擇 Preferences → Plugins → Browse repositories

"

判空災難

高級工程師系列之在Java中如何優雅地判空

NullPointerException

作為搬磚黨的一族們,我們對判空一定再熟悉不過了,不要跟我說你很少進行判空,除非你喜歡NullPointerException。

不過NullPointerException對於很多猿們來說,也是Exception家族中最親近的一員了。

高級工程師系列之在Java中如何優雅地判空

Wowo

為了避免NullPointerException來找我們,我們經常會進行如下操作。

if (data != null) {
do sth.
}

如果一個類中多次使用某個對象,那你可能要一頓操作,so:

高級工程師系列之在Java中如何優雅地判空

1

“世界第九大奇蹟”就這樣誕生了。Maybe你會想,項目中肯定不止你一個人會這樣一頓操作,然後按下Command+Shift+F,真相就在眼前:

高級工程師系列之在Java中如何優雅地判空

2

What,我們有接近一萬行的代碼都是在判空?

高級工程師系列之在Java中如何優雅地判空

3

好了,接下來,要進入正題了。

NullObject模式

對於項目中無數次的判空,對代碼質量整潔度產生了十分之惡劣的影響,對於這種現象,我們稱之為“判空災難”。

那麼,這種現象如何治理呢,你可能聽說過NullObject模式,不過這不是我們今天的武器,但是還是需要介紹一下NullObject模式。

什麼是NullObject模式呢?

In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral ("null") behavior. The null object design pattern describes the uses of such objects and their behavior (or lack thereof).

以上解析來自Wikipedia。

NullObject模式首次發表在“ 程序設計模式語言 ”系列叢書中。一般的,在面嚮對象語言中,對對象的調用前需要使用判空檢查,來判斷這些對象是否為空,因為在空引用上無法調用所需方法。

空對象模式的一種典型實現方式如下圖所示(圖片來自網絡):

高級工程師系列之在Java中如何優雅地判空

4

示例代碼如下(命名來自網絡,哈哈到底是有多懶):

Nullable是空對象的相關操作接口,用於確定對象是否為空,因為在空對象模式中,對象為空會被包裝成一個Object,成為Null Object,該對象會對原有對象的所有方法進行空實現。。

public interface Nullable {

boolean isNull();

}

這個接口定義了業務對象的行為。

public interface DependencyBase extends Nullable {
void Operation();
}

這是該對象的真實類,實現了業務行為接口DependencyBase與空對象操作接口Nullable。

public class Dependency implements DependencyBase, Nullable {
@Override
public void Operation() {
System.out.print("Test!");
}
@Override
public boolean isNull() {
return false;
}

}

這是空對象,對原有對象的行為進行了空實現。

public class NullObject implements DependencyBase{
@Override
public void Operation() {
// do nothing
}
@Override
public boolean isNull() {
return true;
}

}

在使用時,可以通過工廠調用方式來進行空對象的調用,也可以通過其他如反射的方式對對象進行調用(一般多耗時幾毫秒)在此不進行詳細敘述。

public class Factory {

public static DependencyBase get(Nullable dependencyBase){
if (dependencyBase == null){
return new NullObject();
}
return new Dependency();
}

}

這是一個使用範例,通過這種模式,我們不再需要進行對象的判空操作,而是可以直接使用對象,也不必擔心NPE(NullPointerException)的問題。

public class Client {
public void test(DependencyBase dependencyBase){
Factory.get(dependencyBase).Operation();
}
}

關於空對象模式,更具體的內容大家也可以多找一找資料,上述只是對NullObject的簡單介紹,但是,今天我要推薦的是一款協助判空的插件NR Null Object,讓我們來優雅地進行判空,不再進行一頓操作來定義繁瑣的空對象接口與空獨享實現類。

.NR Null Object

NR Null Object是一款適用於Android Studio、IntelliJ IDEA、PhpStorm、WebStorm、PyCharm、RubyMine、AppCode、CLion、GoLand、DataGrip等IDEA的Intellij插件。其可以根據現有對象,便捷快速生成其空對象模式需要的組成成分,其包含功能如下:

  • 分析所選類可聲明為接口的方法;
  • 抽象出公有接口;
  • 創建空對象,自動實現公有接口;
  • 對部分函數進行可為空聲明;
  • 可追加函數進行再次生成;
  • 自動的函數命名規範

讓我們來看一個使用範例:

高級工程師系列之在Java中如何優雅地判空

5

怎麼樣,看起來是不是非常快速便捷,只需要在原有需要進行多次判空的對象中,郵件彈出菜單,選擇Generate,並選擇NR Null Object即可自動生成相應的空對象組件。

那麼如何來獲得這款插件呢?

安裝方式

可以直接通過IDEA的Preferences中的Plugins倉庫進行安裝。

選擇 Preferences → Plugins → Browse repositories

高級工程師系列之在Java中如何優雅地判空

6

搜索“NR Null Oject”或者“Null Oject”進行模糊查詢,點擊右側的Install,restart IDEA即可。

"

判空災難

高級工程師系列之在Java中如何優雅地判空

NullPointerException

作為搬磚黨的一族們,我們對判空一定再熟悉不過了,不要跟我說你很少進行判空,除非你喜歡NullPointerException。

不過NullPointerException對於很多猿們來說,也是Exception家族中最親近的一員了。

高級工程師系列之在Java中如何優雅地判空

Wowo

為了避免NullPointerException來找我們,我們經常會進行如下操作。

if (data != null) {
do sth.
}

如果一個類中多次使用某個對象,那你可能要一頓操作,so:

高級工程師系列之在Java中如何優雅地判空

1

“世界第九大奇蹟”就這樣誕生了。Maybe你會想,項目中肯定不止你一個人會這樣一頓操作,然後按下Command+Shift+F,真相就在眼前:

高級工程師系列之在Java中如何優雅地判空

2

What,我們有接近一萬行的代碼都是在判空?

高級工程師系列之在Java中如何優雅地判空

3

好了,接下來,要進入正題了。

NullObject模式

對於項目中無數次的判空,對代碼質量整潔度產生了十分之惡劣的影響,對於這種現象,我們稱之為“判空災難”。

那麼,這種現象如何治理呢,你可能聽說過NullObject模式,不過這不是我們今天的武器,但是還是需要介紹一下NullObject模式。

什麼是NullObject模式呢?

In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral ("null") behavior. The null object design pattern describes the uses of such objects and their behavior (or lack thereof).

以上解析來自Wikipedia。

NullObject模式首次發表在“ 程序設計模式語言 ”系列叢書中。一般的,在面嚮對象語言中,對對象的調用前需要使用判空檢查,來判斷這些對象是否為空,因為在空引用上無法調用所需方法。

空對象模式的一種典型實現方式如下圖所示(圖片來自網絡):

高級工程師系列之在Java中如何優雅地判空

4

示例代碼如下(命名來自網絡,哈哈到底是有多懶):

Nullable是空對象的相關操作接口,用於確定對象是否為空,因為在空對象模式中,對象為空會被包裝成一個Object,成為Null Object,該對象會對原有對象的所有方法進行空實現。。

public interface Nullable {

boolean isNull();

}

這個接口定義了業務對象的行為。

public interface DependencyBase extends Nullable {
void Operation();
}

這是該對象的真實類,實現了業務行為接口DependencyBase與空對象操作接口Nullable。

public class Dependency implements DependencyBase, Nullable {
@Override
public void Operation() {
System.out.print("Test!");
}
@Override
public boolean isNull() {
return false;
}

}

這是空對象,對原有對象的行為進行了空實現。

public class NullObject implements DependencyBase{
@Override
public void Operation() {
// do nothing
}
@Override
public boolean isNull() {
return true;
}

}

在使用時,可以通過工廠調用方式來進行空對象的調用,也可以通過其他如反射的方式對對象進行調用(一般多耗時幾毫秒)在此不進行詳細敘述。

public class Factory {

public static DependencyBase get(Nullable dependencyBase){
if (dependencyBase == null){
return new NullObject();
}
return new Dependency();
}

}

這是一個使用範例,通過這種模式,我們不再需要進行對象的判空操作,而是可以直接使用對象,也不必擔心NPE(NullPointerException)的問題。

public class Client {
public void test(DependencyBase dependencyBase){
Factory.get(dependencyBase).Operation();
}
}

關於空對象模式,更具體的內容大家也可以多找一找資料,上述只是對NullObject的簡單介紹,但是,今天我要推薦的是一款協助判空的插件NR Null Object,讓我們來優雅地進行判空,不再進行一頓操作來定義繁瑣的空對象接口與空獨享實現類。

.NR Null Object

NR Null Object是一款適用於Android Studio、IntelliJ IDEA、PhpStorm、WebStorm、PyCharm、RubyMine、AppCode、CLion、GoLand、DataGrip等IDEA的Intellij插件。其可以根據現有對象,便捷快速生成其空對象模式需要的組成成分,其包含功能如下:

  • 分析所選類可聲明為接口的方法;
  • 抽象出公有接口;
  • 創建空對象,自動實現公有接口;
  • 對部分函數進行可為空聲明;
  • 可追加函數進行再次生成;
  • 自動的函數命名規範

讓我們來看一個使用範例:

高級工程師系列之在Java中如何優雅地判空

5

怎麼樣,看起來是不是非常快速便捷,只需要在原有需要進行多次判空的對象中,郵件彈出菜單,選擇Generate,並選擇NR Null Object即可自動生成相應的空對象組件。

那麼如何來獲得這款插件呢?

安裝方式

可以直接通過IDEA的Preferences中的Plugins倉庫進行安裝。

選擇 Preferences → Plugins → Browse repositories

高級工程師系列之在Java中如何優雅地判空

6

搜索“NR Null Oject”或者“Null Oject”進行模糊查詢,點擊右側的Install,restart IDEA即可。

高級工程師系列之在Java中如何優雅地判空

7

Optional

還有一種方式是使用Java8特性中的Optional來進行優雅地判空,Optional來自官方的介紹如下:

A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.

一個可能包含也可能不包含非null值的容器對象。 如果存在值,isPresent()將返回true,get()將返回該值。

話不多說,舉個例子。

"

判空災難

高級工程師系列之在Java中如何優雅地判空

NullPointerException

作為搬磚黨的一族們,我們對判空一定再熟悉不過了,不要跟我說你很少進行判空,除非你喜歡NullPointerException。

不過NullPointerException對於很多猿們來說,也是Exception家族中最親近的一員了。

高級工程師系列之在Java中如何優雅地判空

Wowo

為了避免NullPointerException來找我們,我們經常會進行如下操作。

if (data != null) {
do sth.
}

如果一個類中多次使用某個對象,那你可能要一頓操作,so:

高級工程師系列之在Java中如何優雅地判空

1

“世界第九大奇蹟”就這樣誕生了。Maybe你會想,項目中肯定不止你一個人會這樣一頓操作,然後按下Command+Shift+F,真相就在眼前:

高級工程師系列之在Java中如何優雅地判空

2

What,我們有接近一萬行的代碼都是在判空?

高級工程師系列之在Java中如何優雅地判空

3

好了,接下來,要進入正題了。

NullObject模式

對於項目中無數次的判空,對代碼質量整潔度產生了十分之惡劣的影響,對於這種現象,我們稱之為“判空災難”。

那麼,這種現象如何治理呢,你可能聽說過NullObject模式,不過這不是我們今天的武器,但是還是需要介紹一下NullObject模式。

什麼是NullObject模式呢?

In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral ("null") behavior. The null object design pattern describes the uses of such objects and their behavior (or lack thereof).

以上解析來自Wikipedia。

NullObject模式首次發表在“ 程序設計模式語言 ”系列叢書中。一般的,在面嚮對象語言中,對對象的調用前需要使用判空檢查,來判斷這些對象是否為空,因為在空引用上無法調用所需方法。

空對象模式的一種典型實現方式如下圖所示(圖片來自網絡):

高級工程師系列之在Java中如何優雅地判空

4

示例代碼如下(命名來自網絡,哈哈到底是有多懶):

Nullable是空對象的相關操作接口,用於確定對象是否為空,因為在空對象模式中,對象為空會被包裝成一個Object,成為Null Object,該對象會對原有對象的所有方法進行空實現。。

public interface Nullable {

boolean isNull();

}

這個接口定義了業務對象的行為。

public interface DependencyBase extends Nullable {
void Operation();
}

這是該對象的真實類,實現了業務行為接口DependencyBase與空對象操作接口Nullable。

public class Dependency implements DependencyBase, Nullable {
@Override
public void Operation() {
System.out.print("Test!");
}
@Override
public boolean isNull() {
return false;
}

}

這是空對象,對原有對象的行為進行了空實現。

public class NullObject implements DependencyBase{
@Override
public void Operation() {
// do nothing
}
@Override
public boolean isNull() {
return true;
}

}

在使用時,可以通過工廠調用方式來進行空對象的調用,也可以通過其他如反射的方式對對象進行調用(一般多耗時幾毫秒)在此不進行詳細敘述。

public class Factory {

public static DependencyBase get(Nullable dependencyBase){
if (dependencyBase == null){
return new NullObject();
}
return new Dependency();
}

}

這是一個使用範例,通過這種模式,我們不再需要進行對象的判空操作,而是可以直接使用對象,也不必擔心NPE(NullPointerException)的問題。

public class Client {
public void test(DependencyBase dependencyBase){
Factory.get(dependencyBase).Operation();
}
}

關於空對象模式,更具體的內容大家也可以多找一找資料,上述只是對NullObject的簡單介紹,但是,今天我要推薦的是一款協助判空的插件NR Null Object,讓我們來優雅地進行判空,不再進行一頓操作來定義繁瑣的空對象接口與空獨享實現類。

.NR Null Object

NR Null Object是一款適用於Android Studio、IntelliJ IDEA、PhpStorm、WebStorm、PyCharm、RubyMine、AppCode、CLion、GoLand、DataGrip等IDEA的Intellij插件。其可以根據現有對象,便捷快速生成其空對象模式需要的組成成分,其包含功能如下:

  • 分析所選類可聲明為接口的方法;
  • 抽象出公有接口;
  • 創建空對象,自動實現公有接口;
  • 對部分函數進行可為空聲明;
  • 可追加函數進行再次生成;
  • 自動的函數命名規範

讓我們來看一個使用範例:

高級工程師系列之在Java中如何優雅地判空

5

怎麼樣,看起來是不是非常快速便捷,只需要在原有需要進行多次判空的對象中,郵件彈出菜單,選擇Generate,並選擇NR Null Object即可自動生成相應的空對象組件。

那麼如何來獲得這款插件呢?

安裝方式

可以直接通過IDEA的Preferences中的Plugins倉庫進行安裝。

選擇 Preferences → Plugins → Browse repositories

高級工程師系列之在Java中如何優雅地判空

6

搜索“NR Null Oject”或者“Null Oject”進行模糊查詢,點擊右側的Install,restart IDEA即可。

高級工程師系列之在Java中如何優雅地判空

7

Optional

還有一種方式是使用Java8特性中的Optional來進行優雅地判空,Optional來自官方的介紹如下:

A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.

一個可能包含也可能不包含非null值的容器對象。 如果存在值,isPresent()將返回true,get()將返回該值。

話不多說,舉個例子。

高級工程師系列之在Java中如何優雅地判空

栗子

有如下代碼,需要獲得Test2中的Info信息,但是參數為Test4,我們要一層層的申請,每一層都獲得的對象都可能是空,最後的代碼看起來就像這樣。

 public String testSimple(Test4 test) {
if (test == null) {
return "";
}
if (test.getTest3() == null) {
return "";
}
if (test.getTest3().getTest2() == null) {
return "";
}
if (test.getTest3().getTest2().getInfo() == null) {
return "";
}
return test.getTest3().getTest2().getInfo();
}

但是使用Optional後,整個就都不一樣了。

 public String testOptional(Test test) {
return Optional.ofNullable(test).flatMap(Test::getTest3)
.flatMap(Test3::getTest2)
.map(Test2::getInfo)
.orElse("");
}

1.Optional.ofNullable(test),如果test為空,則返回一個單例空Optional對象,如果非空則返回一個Optional包裝對象,Optional將test包裝;

 public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}

2.flatMap(Test::getTest3)判斷test是否為空,如果為空,繼續返回第一步中的單例Optional對象,否則調用Test的getTest3方法;

 public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}

3.flatMap(Test3::getTest2)同上調用Test3的getTest2方法;

4.map(Test2::getInfo)同flatMap類似,但是flatMap要求Test3::getTest2返回值為Optional類型,而map不需要,flatMap不會多層包裝,map返回會再次包裝Optional;

 public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}

5.orElse("");獲得map中的value,不為空則直接返回value,為空則返回傳入的參數作為默認值。

public T orElse(T other) {
return value != null ? value : other;
}

怎麼樣,使用Optional後我們的代碼是不是瞬間變得非常整潔,或許看到這段代碼你會有很多疑問,針對複雜的一長串判空,Optional有它的優勢,但是對於簡單的判空使用Optional也會增加代碼的閱讀成本、編碼量以及團隊新成員的學習成本。畢竟Optional在現在還並沒有像RxJava那樣流行,它還擁有一定的侷限性。

如果直接使用Java8中的Optional,需要保證安卓API級別在24及以上。

"

判空災難

高級工程師系列之在Java中如何優雅地判空

NullPointerException

作為搬磚黨的一族們,我們對判空一定再熟悉不過了,不要跟我說你很少進行判空,除非你喜歡NullPointerException。

不過NullPointerException對於很多猿們來說,也是Exception家族中最親近的一員了。

高級工程師系列之在Java中如何優雅地判空

Wowo

為了避免NullPointerException來找我們,我們經常會進行如下操作。

if (data != null) {
do sth.
}

如果一個類中多次使用某個對象,那你可能要一頓操作,so:

高級工程師系列之在Java中如何優雅地判空

1

“世界第九大奇蹟”就這樣誕生了。Maybe你會想,項目中肯定不止你一個人會這樣一頓操作,然後按下Command+Shift+F,真相就在眼前:

高級工程師系列之在Java中如何優雅地判空

2

What,我們有接近一萬行的代碼都是在判空?

高級工程師系列之在Java中如何優雅地判空

3

好了,接下來,要進入正題了。

NullObject模式

對於項目中無數次的判空,對代碼質量整潔度產生了十分之惡劣的影響,對於這種現象,我們稱之為“判空災難”。

那麼,這種現象如何治理呢,你可能聽說過NullObject模式,不過這不是我們今天的武器,但是還是需要介紹一下NullObject模式。

什麼是NullObject模式呢?

In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral ("null") behavior. The null object design pattern describes the uses of such objects and their behavior (or lack thereof).

以上解析來自Wikipedia。

NullObject模式首次發表在“ 程序設計模式語言 ”系列叢書中。一般的,在面嚮對象語言中,對對象的調用前需要使用判空檢查,來判斷這些對象是否為空,因為在空引用上無法調用所需方法。

空對象模式的一種典型實現方式如下圖所示(圖片來自網絡):

高級工程師系列之在Java中如何優雅地判空

4

示例代碼如下(命名來自網絡,哈哈到底是有多懶):

Nullable是空對象的相關操作接口,用於確定對象是否為空,因為在空對象模式中,對象為空會被包裝成一個Object,成為Null Object,該對象會對原有對象的所有方法進行空實現。。

public interface Nullable {

boolean isNull();

}

這個接口定義了業務對象的行為。

public interface DependencyBase extends Nullable {
void Operation();
}

這是該對象的真實類,實現了業務行為接口DependencyBase與空對象操作接口Nullable。

public class Dependency implements DependencyBase, Nullable {
@Override
public void Operation() {
System.out.print("Test!");
}
@Override
public boolean isNull() {
return false;
}

}

這是空對象,對原有對象的行為進行了空實現。

public class NullObject implements DependencyBase{
@Override
public void Operation() {
// do nothing
}
@Override
public boolean isNull() {
return true;
}

}

在使用時,可以通過工廠調用方式來進行空對象的調用,也可以通過其他如反射的方式對對象進行調用(一般多耗時幾毫秒)在此不進行詳細敘述。

public class Factory {

public static DependencyBase get(Nullable dependencyBase){
if (dependencyBase == null){
return new NullObject();
}
return new Dependency();
}

}

這是一個使用範例,通過這種模式,我們不再需要進行對象的判空操作,而是可以直接使用對象,也不必擔心NPE(NullPointerException)的問題。

public class Client {
public void test(DependencyBase dependencyBase){
Factory.get(dependencyBase).Operation();
}
}

關於空對象模式,更具體的內容大家也可以多找一找資料,上述只是對NullObject的簡單介紹,但是,今天我要推薦的是一款協助判空的插件NR Null Object,讓我們來優雅地進行判空,不再進行一頓操作來定義繁瑣的空對象接口與空獨享實現類。

.NR Null Object

NR Null Object是一款適用於Android Studio、IntelliJ IDEA、PhpStorm、WebStorm、PyCharm、RubyMine、AppCode、CLion、GoLand、DataGrip等IDEA的Intellij插件。其可以根據現有對象,便捷快速生成其空對象模式需要的組成成分,其包含功能如下:

  • 分析所選類可聲明為接口的方法;
  • 抽象出公有接口;
  • 創建空對象,自動實現公有接口;
  • 對部分函數進行可為空聲明;
  • 可追加函數進行再次生成;
  • 自動的函數命名規範

讓我們來看一個使用範例:

高級工程師系列之在Java中如何優雅地判空

5

怎麼樣,看起來是不是非常快速便捷,只需要在原有需要進行多次判空的對象中,郵件彈出菜單,選擇Generate,並選擇NR Null Object即可自動生成相應的空對象組件。

那麼如何來獲得這款插件呢?

安裝方式

可以直接通過IDEA的Preferences中的Plugins倉庫進行安裝。

選擇 Preferences → Plugins → Browse repositories

高級工程師系列之在Java中如何優雅地判空

6

搜索“NR Null Oject”或者“Null Oject”進行模糊查詢,點擊右側的Install,restart IDEA即可。

高級工程師系列之在Java中如何優雅地判空

7

Optional

還有一種方式是使用Java8特性中的Optional來進行優雅地判空,Optional來自官方的介紹如下:

A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.

一個可能包含也可能不包含非null值的容器對象。 如果存在值,isPresent()將返回true,get()將返回該值。

話不多說,舉個例子。

高級工程師系列之在Java中如何優雅地判空

栗子

有如下代碼,需要獲得Test2中的Info信息,但是參數為Test4,我們要一層層的申請,每一層都獲得的對象都可能是空,最後的代碼看起來就像這樣。

 public String testSimple(Test4 test) {
if (test == null) {
return "";
}
if (test.getTest3() == null) {
return "";
}
if (test.getTest3().getTest2() == null) {
return "";
}
if (test.getTest3().getTest2().getInfo() == null) {
return "";
}
return test.getTest3().getTest2().getInfo();
}

但是使用Optional後,整個就都不一樣了。

 public String testOptional(Test test) {
return Optional.ofNullable(test).flatMap(Test::getTest3)
.flatMap(Test3::getTest2)
.map(Test2::getInfo)
.orElse("");
}

1.Optional.ofNullable(test),如果test為空,則返回一個單例空Optional對象,如果非空則返回一個Optional包裝對象,Optional將test包裝;

 public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}

2.flatMap(Test::getTest3)判斷test是否為空,如果為空,繼續返回第一步中的單例Optional對象,否則調用Test的getTest3方法;

 public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}

3.flatMap(Test3::getTest2)同上調用Test3的getTest2方法;

4.map(Test2::getInfo)同flatMap類似,但是flatMap要求Test3::getTest2返回值為Optional類型,而map不需要,flatMap不會多層包裝,map返回會再次包裝Optional;

 public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}

5.orElse("");獲得map中的value,不為空則直接返回value,為空則返回傳入的參數作為默認值。

public T orElse(T other) {
return value != null ? value : other;
}

怎麼樣,使用Optional後我們的代碼是不是瞬間變得非常整潔,或許看到這段代碼你會有很多疑問,針對複雜的一長串判空,Optional有它的優勢,但是對於簡單的判空使用Optional也會增加代碼的閱讀成本、編碼量以及團隊新成員的學習成本。畢竟Optional在現在還並沒有像RxJava那樣流行,它還擁有一定的侷限性。

如果直接使用Java8中的Optional,需要保證安卓API級別在24及以上。

高級工程師系列之在Java中如何優雅地判空

image-20181124085913887.png

你也可以直接引入Google的Guava。(啥是Guava?來自官方的提示)

Guava is a set of core libraries that includes new collection types (such as multimap and multiset), immutable collections, a graph library, functional types, an in-memory cache, and APIs/utilities for concurrency, I/O, hashing, primitives, reflection, string processing, and much more!

引用方式,就像這樣:

 dependencies {
compile 'com.google.guava:guava:27.0-jre'
// or, for Android:
api 'com.google.guava:guava:27.0-android'
}

不過IDEA默認會顯示黃色,提示讓你將Guava表達式遷移到Java Api上。

"

判空災難

高級工程師系列之在Java中如何優雅地判空

NullPointerException

作為搬磚黨的一族們,我們對判空一定再熟悉不過了,不要跟我說你很少進行判空,除非你喜歡NullPointerException。

不過NullPointerException對於很多猿們來說,也是Exception家族中最親近的一員了。

高級工程師系列之在Java中如何優雅地判空

Wowo

為了避免NullPointerException來找我們,我們經常會進行如下操作。

if (data != null) {
do sth.
}

如果一個類中多次使用某個對象,那你可能要一頓操作,so:

高級工程師系列之在Java中如何優雅地判空

1

“世界第九大奇蹟”就這樣誕生了。Maybe你會想,項目中肯定不止你一個人會這樣一頓操作,然後按下Command+Shift+F,真相就在眼前:

高級工程師系列之在Java中如何優雅地判空

2

What,我們有接近一萬行的代碼都是在判空?

高級工程師系列之在Java中如何優雅地判空

3

好了,接下來,要進入正題了。

NullObject模式

對於項目中無數次的判空,對代碼質量整潔度產生了十分之惡劣的影響,對於這種現象,我們稱之為“判空災難”。

那麼,這種現象如何治理呢,你可能聽說過NullObject模式,不過這不是我們今天的武器,但是還是需要介紹一下NullObject模式。

什麼是NullObject模式呢?

In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral ("null") behavior. The null object design pattern describes the uses of such objects and their behavior (or lack thereof).

以上解析來自Wikipedia。

NullObject模式首次發表在“ 程序設計模式語言 ”系列叢書中。一般的,在面嚮對象語言中,對對象的調用前需要使用判空檢查,來判斷這些對象是否為空,因為在空引用上無法調用所需方法。

空對象模式的一種典型實現方式如下圖所示(圖片來自網絡):

高級工程師系列之在Java中如何優雅地判空

4

示例代碼如下(命名來自網絡,哈哈到底是有多懶):

Nullable是空對象的相關操作接口,用於確定對象是否為空,因為在空對象模式中,對象為空會被包裝成一個Object,成為Null Object,該對象會對原有對象的所有方法進行空實現。。

public interface Nullable {

boolean isNull();

}

這個接口定義了業務對象的行為。

public interface DependencyBase extends Nullable {
void Operation();
}

這是該對象的真實類,實現了業務行為接口DependencyBase與空對象操作接口Nullable。

public class Dependency implements DependencyBase, Nullable {
@Override
public void Operation() {
System.out.print("Test!");
}
@Override
public boolean isNull() {
return false;
}

}

這是空對象,對原有對象的行為進行了空實現。

public class NullObject implements DependencyBase{
@Override
public void Operation() {
// do nothing
}
@Override
public boolean isNull() {
return true;
}

}

在使用時,可以通過工廠調用方式來進行空對象的調用,也可以通過其他如反射的方式對對象進行調用(一般多耗時幾毫秒)在此不進行詳細敘述。

public class Factory {

public static DependencyBase get(Nullable dependencyBase){
if (dependencyBase == null){
return new NullObject();
}
return new Dependency();
}

}

這是一個使用範例,通過這種模式,我們不再需要進行對象的判空操作,而是可以直接使用對象,也不必擔心NPE(NullPointerException)的問題。

public class Client {
public void test(DependencyBase dependencyBase){
Factory.get(dependencyBase).Operation();
}
}

關於空對象模式,更具體的內容大家也可以多找一找資料,上述只是對NullObject的簡單介紹,但是,今天我要推薦的是一款協助判空的插件NR Null Object,讓我們來優雅地進行判空,不再進行一頓操作來定義繁瑣的空對象接口與空獨享實現類。

.NR Null Object

NR Null Object是一款適用於Android Studio、IntelliJ IDEA、PhpStorm、WebStorm、PyCharm、RubyMine、AppCode、CLion、GoLand、DataGrip等IDEA的Intellij插件。其可以根據現有對象,便捷快速生成其空對象模式需要的組成成分,其包含功能如下:

  • 分析所選類可聲明為接口的方法;
  • 抽象出公有接口;
  • 創建空對象,自動實現公有接口;
  • 對部分函數進行可為空聲明;
  • 可追加函數進行再次生成;
  • 自動的函數命名規範

讓我們來看一個使用範例:

高級工程師系列之在Java中如何優雅地判空

5

怎麼樣,看起來是不是非常快速便捷,只需要在原有需要進行多次判空的對象中,郵件彈出菜單,選擇Generate,並選擇NR Null Object即可自動生成相應的空對象組件。

那麼如何來獲得這款插件呢?

安裝方式

可以直接通過IDEA的Preferences中的Plugins倉庫進行安裝。

選擇 Preferences → Plugins → Browse repositories

高級工程師系列之在Java中如何優雅地判空

6

搜索“NR Null Oject”或者“Null Oject”進行模糊查詢,點擊右側的Install,restart IDEA即可。

高級工程師系列之在Java中如何優雅地判空

7

Optional

還有一種方式是使用Java8特性中的Optional來進行優雅地判空,Optional來自官方的介紹如下:

A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.

一個可能包含也可能不包含非null值的容器對象。 如果存在值,isPresent()將返回true,get()將返回該值。

話不多說,舉個例子。

高級工程師系列之在Java中如何優雅地判空

栗子

有如下代碼,需要獲得Test2中的Info信息,但是參數為Test4,我們要一層層的申請,每一層都獲得的對象都可能是空,最後的代碼看起來就像這樣。

 public String testSimple(Test4 test) {
if (test == null) {
return "";
}
if (test.getTest3() == null) {
return "";
}
if (test.getTest3().getTest2() == null) {
return "";
}
if (test.getTest3().getTest2().getInfo() == null) {
return "";
}
return test.getTest3().getTest2().getInfo();
}

但是使用Optional後,整個就都不一樣了。

 public String testOptional(Test test) {
return Optional.ofNullable(test).flatMap(Test::getTest3)
.flatMap(Test3::getTest2)
.map(Test2::getInfo)
.orElse("");
}

1.Optional.ofNullable(test),如果test為空,則返回一個單例空Optional對象,如果非空則返回一個Optional包裝對象,Optional將test包裝;

 public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}

2.flatMap(Test::getTest3)判斷test是否為空,如果為空,繼續返回第一步中的單例Optional對象,否則調用Test的getTest3方法;

 public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}

3.flatMap(Test3::getTest2)同上調用Test3的getTest2方法;

4.map(Test2::getInfo)同flatMap類似,但是flatMap要求Test3::getTest2返回值為Optional類型,而map不需要,flatMap不會多層包裝,map返回會再次包裝Optional;

 public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}

5.orElse("");獲得map中的value,不為空則直接返回value,為空則返回傳入的參數作為默認值。

public T orElse(T other) {
return value != null ? value : other;
}

怎麼樣,使用Optional後我們的代碼是不是瞬間變得非常整潔,或許看到這段代碼你會有很多疑問,針對複雜的一長串判空,Optional有它的優勢,但是對於簡單的判空使用Optional也會增加代碼的閱讀成本、編碼量以及團隊新成員的學習成本。畢竟Optional在現在還並沒有像RxJava那樣流行,它還擁有一定的侷限性。

如果直接使用Java8中的Optional,需要保證安卓API級別在24及以上。

高級工程師系列之在Java中如何優雅地判空

image-20181124085913887.png

你也可以直接引入Google的Guava。(啥是Guava?來自官方的提示)

Guava is a set of core libraries that includes new collection types (such as multimap and multiset), immutable collections, a graph library, functional types, an in-memory cache, and APIs/utilities for concurrency, I/O, hashing, primitives, reflection, string processing, and much more!

引用方式,就像這樣:

 dependencies {
compile 'com.google.guava:guava:27.0-jre'
// or, for Android:
api 'com.google.guava:guava:27.0-android'
}

不過IDEA默認會顯示黃色,提示讓你將Guava表達式遷移到Java Api上。

高級工程師系列之在Java中如何優雅地判空

image-3.png

當然,你也可以通過在Preferences搜索"Guava"來Kill掉這個Yellow的提示。

"

判空災難

高級工程師系列之在Java中如何優雅地判空

NullPointerException

作為搬磚黨的一族們,我們對判空一定再熟悉不過了,不要跟我說你很少進行判空,除非你喜歡NullPointerException。

不過NullPointerException對於很多猿們來說,也是Exception家族中最親近的一員了。

高級工程師系列之在Java中如何優雅地判空

Wowo

為了避免NullPointerException來找我們,我們經常會進行如下操作。

if (data != null) {
do sth.
}

如果一個類中多次使用某個對象,那你可能要一頓操作,so:

高級工程師系列之在Java中如何優雅地判空

1

“世界第九大奇蹟”就這樣誕生了。Maybe你會想,項目中肯定不止你一個人會這樣一頓操作,然後按下Command+Shift+F,真相就在眼前:

高級工程師系列之在Java中如何優雅地判空

2

What,我們有接近一萬行的代碼都是在判空?

高級工程師系列之在Java中如何優雅地判空

3

好了,接下來,要進入正題了。

NullObject模式

對於項目中無數次的判空,對代碼質量整潔度產生了十分之惡劣的影響,對於這種現象,我們稱之為“判空災難”。

那麼,這種現象如何治理呢,你可能聽說過NullObject模式,不過這不是我們今天的武器,但是還是需要介紹一下NullObject模式。

什麼是NullObject模式呢?

In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral ("null") behavior. The null object design pattern describes the uses of such objects and their behavior (or lack thereof).

以上解析來自Wikipedia。

NullObject模式首次發表在“ 程序設計模式語言 ”系列叢書中。一般的,在面嚮對象語言中,對對象的調用前需要使用判空檢查,來判斷這些對象是否為空,因為在空引用上無法調用所需方法。

空對象模式的一種典型實現方式如下圖所示(圖片來自網絡):

高級工程師系列之在Java中如何優雅地判空

4

示例代碼如下(命名來自網絡,哈哈到底是有多懶):

Nullable是空對象的相關操作接口,用於確定對象是否為空,因為在空對象模式中,對象為空會被包裝成一個Object,成為Null Object,該對象會對原有對象的所有方法進行空實現。。

public interface Nullable {

boolean isNull();

}

這個接口定義了業務對象的行為。

public interface DependencyBase extends Nullable {
void Operation();
}

這是該對象的真實類,實現了業務行為接口DependencyBase與空對象操作接口Nullable。

public class Dependency implements DependencyBase, Nullable {
@Override
public void Operation() {
System.out.print("Test!");
}
@Override
public boolean isNull() {
return false;
}

}

這是空對象,對原有對象的行為進行了空實現。

public class NullObject implements DependencyBase{
@Override
public void Operation() {
// do nothing
}
@Override
public boolean isNull() {
return true;
}

}

在使用時,可以通過工廠調用方式來進行空對象的調用,也可以通過其他如反射的方式對對象進行調用(一般多耗時幾毫秒)在此不進行詳細敘述。

public class Factory {

public static DependencyBase get(Nullable dependencyBase){
if (dependencyBase == null){
return new NullObject();
}
return new Dependency();
}

}

這是一個使用範例,通過這種模式,我們不再需要進行對象的判空操作,而是可以直接使用對象,也不必擔心NPE(NullPointerException)的問題。

public class Client {
public void test(DependencyBase dependencyBase){
Factory.get(dependencyBase).Operation();
}
}

關於空對象模式,更具體的內容大家也可以多找一找資料,上述只是對NullObject的簡單介紹,但是,今天我要推薦的是一款協助判空的插件NR Null Object,讓我們來優雅地進行判空,不再進行一頓操作來定義繁瑣的空對象接口與空獨享實現類。

.NR Null Object

NR Null Object是一款適用於Android Studio、IntelliJ IDEA、PhpStorm、WebStorm、PyCharm、RubyMine、AppCode、CLion、GoLand、DataGrip等IDEA的Intellij插件。其可以根據現有對象,便捷快速生成其空對象模式需要的組成成分,其包含功能如下:

  • 分析所選類可聲明為接口的方法;
  • 抽象出公有接口;
  • 創建空對象,自動實現公有接口;
  • 對部分函數進行可為空聲明;
  • 可追加函數進行再次生成;
  • 自動的函數命名規範

讓我們來看一個使用範例:

高級工程師系列之在Java中如何優雅地判空

5

怎麼樣,看起來是不是非常快速便捷,只需要在原有需要進行多次判空的對象中,郵件彈出菜單,選擇Generate,並選擇NR Null Object即可自動生成相應的空對象組件。

那麼如何來獲得這款插件呢?

安裝方式

可以直接通過IDEA的Preferences中的Plugins倉庫進行安裝。

選擇 Preferences → Plugins → Browse repositories

高級工程師系列之在Java中如何優雅地判空

6

搜索“NR Null Oject”或者“Null Oject”進行模糊查詢,點擊右側的Install,restart IDEA即可。

高級工程師系列之在Java中如何優雅地判空

7

Optional

還有一種方式是使用Java8特性中的Optional來進行優雅地判空,Optional來自官方的介紹如下:

A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.

一個可能包含也可能不包含非null值的容器對象。 如果存在值,isPresent()將返回true,get()將返回該值。

話不多說,舉個例子。

高級工程師系列之在Java中如何優雅地判空

栗子

有如下代碼,需要獲得Test2中的Info信息,但是參數為Test4,我們要一層層的申請,每一層都獲得的對象都可能是空,最後的代碼看起來就像這樣。

 public String testSimple(Test4 test) {
if (test == null) {
return "";
}
if (test.getTest3() == null) {
return "";
}
if (test.getTest3().getTest2() == null) {
return "";
}
if (test.getTest3().getTest2().getInfo() == null) {
return "";
}
return test.getTest3().getTest2().getInfo();
}

但是使用Optional後,整個就都不一樣了。

 public String testOptional(Test test) {
return Optional.ofNullable(test).flatMap(Test::getTest3)
.flatMap(Test3::getTest2)
.map(Test2::getInfo)
.orElse("");
}

1.Optional.ofNullable(test),如果test為空,則返回一個單例空Optional對象,如果非空則返回一個Optional包裝對象,Optional將test包裝;

 public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}

2.flatMap(Test::getTest3)判斷test是否為空,如果為空,繼續返回第一步中的單例Optional對象,否則調用Test的getTest3方法;

 public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}

3.flatMap(Test3::getTest2)同上調用Test3的getTest2方法;

4.map(Test2::getInfo)同flatMap類似,但是flatMap要求Test3::getTest2返回值為Optional類型,而map不需要,flatMap不會多層包裝,map返回會再次包裝Optional;

 public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}

5.orElse("");獲得map中的value,不為空則直接返回value,為空則返回傳入的參數作為默認值。

public T orElse(T other) {
return value != null ? value : other;
}

怎麼樣,使用Optional後我們的代碼是不是瞬間變得非常整潔,或許看到這段代碼你會有很多疑問,針對複雜的一長串判空,Optional有它的優勢,但是對於簡單的判空使用Optional也會增加代碼的閱讀成本、編碼量以及團隊新成員的學習成本。畢竟Optional在現在還並沒有像RxJava那樣流行,它還擁有一定的侷限性。

如果直接使用Java8中的Optional,需要保證安卓API級別在24及以上。

高級工程師系列之在Java中如何優雅地判空

image-20181124085913887.png

你也可以直接引入Google的Guava。(啥是Guava?來自官方的提示)

Guava is a set of core libraries that includes new collection types (such as multimap and multiset), immutable collections, a graph library, functional types, an in-memory cache, and APIs/utilities for concurrency, I/O, hashing, primitives, reflection, string processing, and much more!

引用方式,就像這樣:

 dependencies {
compile 'com.google.guava:guava:27.0-jre'
// or, for Android:
api 'com.google.guava:guava:27.0-android'
}

不過IDEA默認會顯示黃色,提示讓你將Guava表達式遷移到Java Api上。

高級工程師系列之在Java中如何優雅地判空

image-3.png

當然,你也可以通過在Preferences搜索"Guava"來Kill掉這個Yellow的提示。

高級工程師系列之在Java中如何優雅地判空

image-4.png

關於Optional使用還有很多技巧,感興趣可以查閱Guava和Java8相關書籍和文檔。

使用Optional具有如下優點:

  1. 將防禦式編程代碼完美包裝
  2. 鏈式調用
  3. 有效避免程序代碼中的空指針

但是也同樣具有一些缺點:

  1. 流行性不是非常理想,團隊新成員需要學習成本
  2. 安卓中需要引入Guava,需要團隊每個人處理IDEA默認提示,或者忍受黃色提示
  3. 有時候代碼閱讀看起來可能會如下圖所示:
"

判空災難

高級工程師系列之在Java中如何優雅地判空

NullPointerException

作為搬磚黨的一族們,我們對判空一定再熟悉不過了,不要跟我說你很少進行判空,除非你喜歡NullPointerException。

不過NullPointerException對於很多猿們來說,也是Exception家族中最親近的一員了。

高級工程師系列之在Java中如何優雅地判空

Wowo

為了避免NullPointerException來找我們,我們經常會進行如下操作。

if (data != null) {
do sth.
}

如果一個類中多次使用某個對象,那你可能要一頓操作,so:

高級工程師系列之在Java中如何優雅地判空

1

“世界第九大奇蹟”就這樣誕生了。Maybe你會想,項目中肯定不止你一個人會這樣一頓操作,然後按下Command+Shift+F,真相就在眼前:

高級工程師系列之在Java中如何優雅地判空

2

What,我們有接近一萬行的代碼都是在判空?

高級工程師系列之在Java中如何優雅地判空

3

好了,接下來,要進入正題了。

NullObject模式

對於項目中無數次的判空,對代碼質量整潔度產生了十分之惡劣的影響,對於這種現象,我們稱之為“判空災難”。

那麼,這種現象如何治理呢,你可能聽說過NullObject模式,不過這不是我們今天的武器,但是還是需要介紹一下NullObject模式。

什麼是NullObject模式呢?

In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral ("null") behavior. The null object design pattern describes the uses of such objects and their behavior (or lack thereof).

以上解析來自Wikipedia。

NullObject模式首次發表在“ 程序設計模式語言 ”系列叢書中。一般的,在面嚮對象語言中,對對象的調用前需要使用判空檢查,來判斷這些對象是否為空,因為在空引用上無法調用所需方法。

空對象模式的一種典型實現方式如下圖所示(圖片來自網絡):

高級工程師系列之在Java中如何優雅地判空

4

示例代碼如下(命名來自網絡,哈哈到底是有多懶):

Nullable是空對象的相關操作接口,用於確定對象是否為空,因為在空對象模式中,對象為空會被包裝成一個Object,成為Null Object,該對象會對原有對象的所有方法進行空實現。。

public interface Nullable {

boolean isNull();

}

這個接口定義了業務對象的行為。

public interface DependencyBase extends Nullable {
void Operation();
}

這是該對象的真實類,實現了業務行為接口DependencyBase與空對象操作接口Nullable。

public class Dependency implements DependencyBase, Nullable {
@Override
public void Operation() {
System.out.print("Test!");
}
@Override
public boolean isNull() {
return false;
}

}

這是空對象,對原有對象的行為進行了空實現。

public class NullObject implements DependencyBase{
@Override
public void Operation() {
// do nothing
}
@Override
public boolean isNull() {
return true;
}

}

在使用時,可以通過工廠調用方式來進行空對象的調用,也可以通過其他如反射的方式對對象進行調用(一般多耗時幾毫秒)在此不進行詳細敘述。

public class Factory {

public static DependencyBase get(Nullable dependencyBase){
if (dependencyBase == null){
return new NullObject();
}
return new Dependency();
}

}

這是一個使用範例,通過這種模式,我們不再需要進行對象的判空操作,而是可以直接使用對象,也不必擔心NPE(NullPointerException)的問題。

public class Client {
public void test(DependencyBase dependencyBase){
Factory.get(dependencyBase).Operation();
}
}

關於空對象模式,更具體的內容大家也可以多找一找資料,上述只是對NullObject的簡單介紹,但是,今天我要推薦的是一款協助判空的插件NR Null Object,讓我們來優雅地進行判空,不再進行一頓操作來定義繁瑣的空對象接口與空獨享實現類。

.NR Null Object

NR Null Object是一款適用於Android Studio、IntelliJ IDEA、PhpStorm、WebStorm、PyCharm、RubyMine、AppCode、CLion、GoLand、DataGrip等IDEA的Intellij插件。其可以根據現有對象,便捷快速生成其空對象模式需要的組成成分,其包含功能如下:

  • 分析所選類可聲明為接口的方法;
  • 抽象出公有接口;
  • 創建空對象,自動實現公有接口;
  • 對部分函數進行可為空聲明;
  • 可追加函數進行再次生成;
  • 自動的函數命名規範

讓我們來看一個使用範例:

高級工程師系列之在Java中如何優雅地判空

5

怎麼樣,看起來是不是非常快速便捷,只需要在原有需要進行多次判空的對象中,郵件彈出菜單,選擇Generate,並選擇NR Null Object即可自動生成相應的空對象組件。

那麼如何來獲得這款插件呢?

安裝方式

可以直接通過IDEA的Preferences中的Plugins倉庫進行安裝。

選擇 Preferences → Plugins → Browse repositories

高級工程師系列之在Java中如何優雅地判空

6

搜索“NR Null Oject”或者“Null Oject”進行模糊查詢,點擊右側的Install,restart IDEA即可。

高級工程師系列之在Java中如何優雅地判空

7

Optional

還有一種方式是使用Java8特性中的Optional來進行優雅地判空,Optional來自官方的介紹如下:

A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.

一個可能包含也可能不包含非null值的容器對象。 如果存在值,isPresent()將返回true,get()將返回該值。

話不多說,舉個例子。

高級工程師系列之在Java中如何優雅地判空

栗子

有如下代碼,需要獲得Test2中的Info信息,但是參數為Test4,我們要一層層的申請,每一層都獲得的對象都可能是空,最後的代碼看起來就像這樣。

 public String testSimple(Test4 test) {
if (test == null) {
return "";
}
if (test.getTest3() == null) {
return "";
}
if (test.getTest3().getTest2() == null) {
return "";
}
if (test.getTest3().getTest2().getInfo() == null) {
return "";
}
return test.getTest3().getTest2().getInfo();
}

但是使用Optional後,整個就都不一樣了。

 public String testOptional(Test test) {
return Optional.ofNullable(test).flatMap(Test::getTest3)
.flatMap(Test3::getTest2)
.map(Test2::getInfo)
.orElse("");
}

1.Optional.ofNullable(test),如果test為空,則返回一個單例空Optional對象,如果非空則返回一個Optional包裝對象,Optional將test包裝;

 public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}

2.flatMap(Test::getTest3)判斷test是否為空,如果為空,繼續返回第一步中的單例Optional對象,否則調用Test的getTest3方法;

 public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}

3.flatMap(Test3::getTest2)同上調用Test3的getTest2方法;

4.map(Test2::getInfo)同flatMap類似,但是flatMap要求Test3::getTest2返回值為Optional類型,而map不需要,flatMap不會多層包裝,map返回會再次包裝Optional;

 public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}

5.orElse("");獲得map中的value,不為空則直接返回value,為空則返回傳入的參數作為默認值。

public T orElse(T other) {
return value != null ? value : other;
}

怎麼樣,使用Optional後我們的代碼是不是瞬間變得非常整潔,或許看到這段代碼你會有很多疑問,針對複雜的一長串判空,Optional有它的優勢,但是對於簡單的判空使用Optional也會增加代碼的閱讀成本、編碼量以及團隊新成員的學習成本。畢竟Optional在現在還並沒有像RxJava那樣流行,它還擁有一定的侷限性。

如果直接使用Java8中的Optional,需要保證安卓API級別在24及以上。

高級工程師系列之在Java中如何優雅地判空

image-20181124085913887.png

你也可以直接引入Google的Guava。(啥是Guava?來自官方的提示)

Guava is a set of core libraries that includes new collection types (such as multimap and multiset), immutable collections, a graph library, functional types, an in-memory cache, and APIs/utilities for concurrency, I/O, hashing, primitives, reflection, string processing, and much more!

引用方式,就像這樣:

 dependencies {
compile 'com.google.guava:guava:27.0-jre'
// or, for Android:
api 'com.google.guava:guava:27.0-android'
}

不過IDEA默認會顯示黃色,提示讓你將Guava表達式遷移到Java Api上。

高級工程師系列之在Java中如何優雅地判空

image-3.png

當然,你也可以通過在Preferences搜索"Guava"來Kill掉這個Yellow的提示。

高級工程師系列之在Java中如何優雅地判空

image-4.png

關於Optional使用還有很多技巧,感興趣可以查閱Guava和Java8相關書籍和文檔。

使用Optional具有如下優點:

  1. 將防禦式編程代碼完美包裝
  2. 鏈式調用
  3. 有效避免程序代碼中的空指針

但是也同樣具有一些缺點:

  1. 流行性不是非常理想,團隊新成員需要學習成本
  2. 安卓中需要引入Guava,需要團隊每個人處理IDEA默認提示,或者忍受黃色提示
  3. 有時候代碼閱讀看起來可能會如下圖所示:
高級工程師系列之在Java中如何優雅地判空

Duang

Kotlin

當然,Kotlin以具有優秀的空安全性為一大特色,並可以與Java很好的混合使用,like this:

 test1?.test2?.test3?.test4

如果你已經開始使用了Kotlin,可以不用再寫繚亂的防禦判空語句。如果你還沒有使用Kotlin,並不推薦為了判空優雅而直接轉向Kotlin。

寫在最後:

碼字不易看到最後了,那就點個關注唄,只收藏不點關注的都是在耍流氓!

關注並私信我“架構”,免費送一些Java架構資料,先到先得

"

相關推薦

推薦中...