Java for each循环引发NullPointException
以下java段将导致NullPointException,因为变量列表为null,它将传递给for each循环Java for each循环引发NullPointException,java,loops,for-loop,Java,Loops,For Loop,以下java段将导致NullPointException,因为变量列表为null,它将传递给for each循环 List<> arr = null; for (Object o : arr) { System.out.println("ln "+o); } 在这两种情况下,arr为null都会导致arr.length或arr.iterator()引发NullPointException 我只是好奇为什么(objecto:arr){}的没有被翻译成 if (arr!=nul
List<> arr = null;
for (Object o : arr) {
System.out.println("ln "+o);
}
在这两种情况下,arr为null都会导致arr.length或arr.iterator()引发NullPointException
我只是好奇为什么(objecto:arr){}的没有被翻译成
if (arr!=null){
for (int i = 0; i < arr.length; i++) {
}
}
and
if (arr!=null){
for (Iterator<type> iter = arr.iterator(); iter.hasNext(); ){
type var = iter.next();
}
}
if(arr!=null){
对于(int i=0;i
包括arr=空表达式可以减少代码嵌套。“我认为for(Object o:arr){}相当于
对于(int i=0;i
你为什么这么想?如果arr为null,arr.length如何不引发异常?
null不能有长度
如果for(Object o:arr)
没有抛出异常,这意味着for(:)循环足够聪明,可以检查arr是否为null,而不是尝试从中提取项。显然,for(;;)循环没有那么聪明。如果(o!=null)
保护,避免出现空指针异常通常不是一个好主意-如果o
为空,在这种情况下,如果结果是这样,您希望抛出并记录异常。它不插入空检查的原因是因为它没有定义为空。您可以在Java语言规范的第14.14.2节中找到foreach循环的规则
至于为什么它是这样设计的,更大的问题是为什么不是
- 这是自然的。foreach循环的行为类似于for循环,没有神奇的行为
- 这是需要的。人们通常不希望代码在错误发生时以静默方式失败
阿尔文·王(Alvin Wong)提出的绩效问题充其量只是一个次要考虑。JVM通常会在变量始终为非空的情况下优化空检查,因此性能影响可以忽略不计。我看到了以下原因,尽管我不知道是否有人考虑过这一点,它是在何时实现的,以及实际原因是什么
正如您所演示的,for(:)-循环的当前行为非常容易理解。另一种行为不是
它将是java世界中唯一以这种方式运行的东西
它并不等同于简单的for循环,因此在这两者之间进行迁移实际上并不等同
不管怎样,使用null是一个坏习惯,因此NPE是一种很好的方式,可以告诉开发人员“你搞砸了,收拾你的烂摊子”,建议的行为会隐藏问题
如果要在循环之前或之后对数组执行其他操作,该怎么办。。。现在,您将在代码中进行两次空检查
您已经回答了您的问题,如果arr为null,则arr.lenght抛出NullPointerException。因此,for(Object o:arr){}
相当于
for (int i = 0; i < arr.length; i++) { }
for(inti=0;i
回答第一个问题:不,这三个循环不相等。第二,在这些循环中找不到空检查;试图迭代那些不存在的东西是没有任何意义的
假设我们有以下类:
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class EnhancedFor {
private List<Integer> dummyList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
private List<Integer> nullList = null;
public void enhancedForDummyList() {
for(Integer i : dummyList) {
System.out.println(i);
}
}
public void iteratorDummyList() {
for(Iterator<Integer> iterator = dummyList.iterator(); iterator.hasNext();) {
System.out.println(iterator.next());
}
}
public void normalLoopDummyList() {
for(int i = 0; i < dummyList.size(); i++) {
System.out.println(dummyList.get(i));
}
}
}
下面是迭代器的字节码
public iteratorDummyList()V
L0
LINENUMBER 24 L0
ALOAD 0
GETFIELD EnhancedFor.dummyList : Ljava/util/List;
INVOKEINTERFACE java/util/List.iterator ()Ljava/util/Iterator;
ASTORE 1
L1
FRAME APPEND [java/util/Iterator]
ALOAD 1
INVOKEINTERFACE java/util/Iterator.hasNext ()Z
IFEQ L2
L3
LINENUMBER 25 L3
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 1
INVOKEINTERFACE java/util/Iterator.next ()Ljava/lang/Object;
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
GOTO L1
L2
LINENUMBER 27 L2
FRAME CHOP 1
RETURN
L4
LOCALVARIABLE iterator Ljava/util/Iterator; L1 L2 1
// signature Ljava/util/Iterator<Ljava/lang/Integer;>;
// declaration: java.util.Iterator<java.lang.Integer>
LOCALVARIABLE this LEnhancedFor; L0 L4 0
MAXSTACK = 2
MAXLOCALS = 2
它正在做一些不同的事情。它根本没有使用迭代器
接口。相反,我们正在调用get()
,它只由列表指定,而不是迭代器
3.结论
有一个合理的理由可以解释为什么我们要取消引用的列表被假定为非空-我们正在调用接口指定的方法。如果没有实现这些方法,那就不同了:抛出一个UnsupportedOperationException
。如果我们试图在其上调用约定的对象不存在-这根本没有意义。如果我有一个空的ArrayList,那么它包含多少个对象?我的答案是零。所以在我看来,增强的for循环不应该为
List<Object> myList = null;
for (Object obj : myList) {
System.out.println(obj.toString());
}
List myList=null;
用于(对象对象对象:myList){
System.out.println(obj.toString());
}
但确实如此。显然,java规范中的这一点现在不会改变,因此可能他们应该引入elvis和安全导航操作符,以支持这一点:
List<Object> myList = null;
for (Object obj ?: myList) {
System.out.println(obj?.toString());
}
List myList=null;
对于(对象对象?:myList){
System.out.println(obj?.toString());
}
然后,开发人员可以选择是抛出NPE还是优雅地处理空集合 循环null将导致NullPointerException
,因此您必须始终检查列表是否为null,您可以使用以下通用方法:
public static boolean canLoopList(List<?> list) {
if (list != null && !list.isEmpty()) {
return true;
}
return false;
}
如果您知道arr
已经不是null
,是否希望它进行额外的无用null
检查?我想不是。不过,我看不出有什么理由想要迭代已知的空列表。为什么要在增强的for循环中进行null检查,而不是在迭代之前列表永远不为null?我假设“已知null列表”只是为了解释questionfor(对象o:arr)的行为,检查arr是否为null是不明智的(如果它不引发异常,它必须是!)“如果我有一个null
ArrayList
..”是胡说八道。您不能有null
任何内容null
表示您没有。如果没有“It”,问“It”包含多少对象是没有意义的。OTOH,如果您有一个空的ArrayList
,其中包含零个对象;在迭代之前不必检查字段的存在性通常是有用的;特别是对于第三方库,您无法控制列表的实例化。e、 g循环通过CC收件人i
List<Object> myList = null;
for (Object obj : myList) {
System.out.println(obj.toString());
}
List<Object> myList = null;
for (Object obj ?: myList) {
System.out.println(obj?.toString());
}
public static boolean canLoopList(List<?> list) {
if (list != null && !list.isEmpty()) {
return true;
}
return false;
}
if (canLoopList(yourList)) {
for(Type var : yourList) {
...
}
}