Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/384.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java for each循环引发NullPointException_Java_Loops_For Loop - Fatal编程技术网

Java for each循环引发NullPointException

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

以下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!=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) {
        ...
    }
    }