编译器明明可以确定为错误,为什么只报出警告或任何警告错误都不报出?

时间:2022-09-08 19:56:04
package com.test;

public class Test2 {
public static void main(String[] args) {
methodA();
}

public static void methodA() {
// 行1
String s = null;

// 行2
System.out.println(s.length());// 这一行报一个警告:Null pointer access: The variable s can only be null at this location
}

}



疑问1:

多个地方调用Test2类的methodA()方法,都是各自的methodA()方法,对吗?会互不影响,里面的局部变量 s 都会是各自的,对吗?为什么?在底层原理上如何解释?


疑问2:

为什么编译器只给出一个警告而不是错误呢?我认为用人为的方法也没有任何办法使在执行 “行2” 语句时 s 变量不为 null,即是说:s 变量一定为 null,对吗?如果是这样,那编译器就应该报错,而不应该是警告啊,对吗?

编译器为什么设计成只报警告而不是错误呢?是编译器做的粗糙不细的原因吗?下面还有一个例子,请注意看注释处,那里描述的是运行的结果:


public static void main(String[] args) {
List list = new ArrayList();
list = null;
for(Object s: list) {// 编译不报错,运行时,这行会报错:java.lang.NullPointerException
System.out.println(111111);
}
System.out.println(222222);
}


------------------------------------------

疑问3:

再看下面代码:

package com.test;

public class Test2 {
public static void main(String[] args) {
methodA();
}

public static void methodA() {
Object a = new Integer(3); // 行1

String s = (String)a;// 行2

System.out.println(s);
}
}

上面代码编译器没有报出任何的错误和警告。

a 变量中实际装的类型是 Integer,到“行2”代码时,编译器一定能够有办法知道 a 变量中的实际类型,并且人为也没有任何办法使程序运行到 “行2” 时使 a 变量中的数据类型变成非 Integer,因为这是在一个方法中,那么编译器为什么不在 “行2” 就报错呢?而使在运行时报了错?


------------------------------------------

疑问4:

package com.test;

public class Test3 {

public static void main(String[] args) {
int a = test();
System.out.println(a);
}

private static int test() {

int a = 20 / 0;// 行1
System.out.println(a);// 行2

return 0;
}

}


上面代码,编译正常,没有报出任何的警告和错误,我的疑问:编译器为什么不在 “行1” 处报错误呢?而编译器是能够检测到这一行运行的时候一定会出错啊,我认为没有任何办法使 “int a = 20 / 0;” 这行语句在运行时变化而使之不报错,对吗?那编译器为什么不使在编译的时候就使在 “行1” 处报错呢?

3 个解决方案

#1


1、你这个说法有点小问题,methodA由于是static,所以永远只有一个,但是如果多个地方调用methodA,他们的运行环境确实是独立的不同的,也就是说有独立的栈内存,局部变量也当然是不同的,这个去看函数调用原理就知道了。

2 3 4属于同一问题,这只是编译器设计上的问题,不同编译器表现可能不同,你完全可以自己写一个Java编译器检查所有明显错误的情况并报错不予以编译,或者你也可以写一个编译器完全不检查任何潜在错误。
当前版本的官方编译器设计上认为编译器的本职工作只是编译,运行会不会出错和它无关,它在能编译通过的情况下尽量编译,除非是实在无法编译才会报告错误,如果它觉得这个代码可能有问题但可以编译通过,也只会警告,就算在你看来肯定会出错,编译器也是睁一只眼闭一只眼,这一方面是充分相信程序员,另一方面也是效率上的考虑,这类错误太多了,如果所有这些错误你都要去检查,并且做出适当处理,那开销太大,特别是大型项目编译,如果一个项目本来编译只需要一分钟,检查错误却要花上十分钟,那估计没有几个人会喜欢这个编译器,所以有些语言比如C/C++的某些编译器为了效率基本不会检查潜在错误。

#2


追问:

疑问 1 中的代码:

public static void methodA() {
  // 行1
  String s = null;

  // 行2
  System.out.println(s.length());
}


疑问5:想尽一切的办法,是否有方法能够使在执行 “行2” 代码时,使 s 变量的值不为 null ?

我想过多线程,但也认为无法做到,因为这是一个方法,是一个方法中的局部变量,每个线程执行此方法,都会是 “各自单独” 地去执行此方法。

#3


该回复于2014-09-22 08:45:03被管理员删除

#1


1、你这个说法有点小问题,methodA由于是static,所以永远只有一个,但是如果多个地方调用methodA,他们的运行环境确实是独立的不同的,也就是说有独立的栈内存,局部变量也当然是不同的,这个去看函数调用原理就知道了。

2 3 4属于同一问题,这只是编译器设计上的问题,不同编译器表现可能不同,你完全可以自己写一个Java编译器检查所有明显错误的情况并报错不予以编译,或者你也可以写一个编译器完全不检查任何潜在错误。
当前版本的官方编译器设计上认为编译器的本职工作只是编译,运行会不会出错和它无关,它在能编译通过的情况下尽量编译,除非是实在无法编译才会报告错误,如果它觉得这个代码可能有问题但可以编译通过,也只会警告,就算在你看来肯定会出错,编译器也是睁一只眼闭一只眼,这一方面是充分相信程序员,另一方面也是效率上的考虑,这类错误太多了,如果所有这些错误你都要去检查,并且做出适当处理,那开销太大,特别是大型项目编译,如果一个项目本来编译只需要一分钟,检查错误却要花上十分钟,那估计没有几个人会喜欢这个编译器,所以有些语言比如C/C++的某些编译器为了效率基本不会检查潜在错误。

#2


追问:

疑问 1 中的代码:

public static void methodA() {
  // 行1
  String s = null;

  // 行2
  System.out.println(s.length());
}


疑问5:想尽一切的办法,是否有方法能够使在执行 “行2” 代码时,使 s 变量的值不为 null ?

我想过多线程,但也认为无法做到,因为这是一个方法,是一个方法中的局部变量,每个线程执行此方法,都会是 “各自单独” 地去执行此方法。

#3


该回复于2014-09-22 08:45:03被管理员删除