文章目錄
1 摘要
java 中 list 是一種常用的集合類(接口),起子類 ArrayList
更是重要的使用廣泛; list 集合允許存在值爲 null
的元素,在操作 list 元素時,值爲 null 的對象可能會導致空指針異常(NullPointException)。下文將模擬 list 集合中 size 大於 0,同時包含 null 元素的情景,並針對該情況在 java 8 環境下給出一定的解決方案。
2 情景模擬
2.1 模擬包含 null 元素的 list 集合
int length = 10;
/**
* list 初始化並賦值
*/
List<Integer> integerList = new ArrayList<>(16);
for (int i = 0; i < length; i++) {
if (i == 5 || i == 8) {
integerList.add(null);
} else {
integerList.add(i);
}
}
/**
* list size
*/
System.out.println("list size: " + integerList.size());
/**
* 打印 list 的每一個元素
*/
integerList.stream().forEach(integer -> {
System.out.println(integer);
// TODO to do something
});
運行結果:
list size: 10
0
1
2
3
4
null
6
7
null
9
從結果可知,list 集合的長度爲 10,其中包含 2 個值爲 null 的元素
2.2 模擬出現空指針異常的場景
try {
integerList.stream().forEach(integer -> {
System.out.println(integer.toString());
// TODO to do something
});
} catch (Exception e) {
e.printStackTrace();
}
運行結果:
0
1
2
3
4
java.lang.NullPointerException
at com.ljq.demo.object.ListDemoTest.lambda$listSize$1(ListDemoTest.java:50)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
at com.ljq.demo.object.ListDemoTest.listSize(ListDemoTest.java:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
在 list 集合包含 null 元素時,如果再來操作 null 對象,則會拋出空指針異常(NullPointerException)
3 解決方案
3.1 當只操作原來的 list 時
如果只需要在原來的 list 中進行操作,後期不再使用該 list 時,可以使用的解決方法:
integerList.stream().filter(Objects::nonNull).forEach(integer -> {
System.out.println(integer.toString());
// TODO to do something
});
java 8 中使用 lambda 表達式進行過濾 null 元素
運行結果:
0
1
2
3
4
6
7
9
3.2 單次引用原來的 list 時
如果原來的 list 需要被引用單次時,可以使用該解決方案:
如將 list 轉化爲 json 字符串,同時過濾 null 元素
try {
String listJsonStr = new ObjectMapper().writeValueAsString(integerList.stream().filter(Objects::nonNull).peek(integer -> {
System.out.println(integer.toString());
// TODO to do something
}).collect(Collectors.toList()));
System.out.println("listJsonStr: " + listJsonStr);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
運行結果:
0
1
2
3
4
6
7
9
listJsonStr: [0,1,2,3,4,6,7,9]
3.3 多次引用,生成新的 list
當需要多次使用該 list,或使用 list 的不同屬性時,可以過濾 null 元素之後生成一個新的 list
在生成新的 list 之後,舊的 list 集合將會被棄用,可能會產生內存垃圾
List<Integer> newIntegerList = integerList.stream().filter(Objects::nonNull).collect(Collectors.toList());
System.out.println("newIntegerList size: " + newIntegerList.size());
// TODO to do something
運行結果:
newIntegerList size: 8
4 完整測試代碼
package com.ljq.demo.object;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public class ListDemoTest {
@Test
public void listSize() {
int length = 10;
/**
* list 初始化並賦值
*/
List<Integer> integerList = new ArrayList<>(16);
for (int i = 0; i < length; i++) {
if (i == 5 || i == 8) {
integerList.add(null);
} else {
integerList.add(i);
}
}
/**
* list size
*/
System.out.println("list size: " + integerList.size());
/**
* 打印 list 的每一個元素
*/
integerList.stream().forEach(integer -> {
System.out.println(integer);
// TODO to do something
});
System.out.println("---------------- 分割線 ----------------------");
/**
* list 中的 null 元素可能導致空指針異常(NullPointerException)
*/
try {
integerList.stream().forEach(integer -> {
System.out.println(integer.toString());
// TODO to do something
});
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("---------------- 分割線 ----------------------");
/**
* java 8 針對 list 集合 null 元素解決方案
*/
/**
* 1) 操作原來的 list
*/
integerList.stream().filter(Objects::nonNull).forEach(integer -> {
System.out.println(integer.toString());
// TODO to do something
});
System.out.println("---------------- 分割線 ----------------------");
/**
* 2) 引用原來的 list
*/
try {
String listJsonStr = new ObjectMapper().writeValueAsString(integerList.stream().filter(Objects::nonNull).peek(integer -> {
System.out.println(integer.toString());
// TODO to do something
}).collect(Collectors.toList()));
System.out.println("listJsonStr: " + listJsonStr);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
System.out.println("---------------- 分割線 ----------------------");
/**
* 3) 生成一個新的 list(原來的 list 可能會產生內存垃圾)
*/
List<Integer> newIntegerList = integerList.stream().filter(Objects::nonNull).collect(Collectors.toList());
System.out.println("newIntegerList size: " + newIntegerList.size());
// TODO to do something
}
}
個人公衆號:404Code,分享半個互聯網人的技術與思考,感興趣的可以關注.