2013-08-22 64 views
0

我期望这个程序给我编译错误,但它编译成功,我运行时得到一个运行时异常。异常而不是编译器错误

class substr11 
{ 

public static void main(String args[]) 
{ 

String s = "abcde"; 

System.out.println(s.substring(1,-1)); 

} 


} 

编译器错误应该能够解析(字符串在人体自身初始化),并发现这串操作会导致编译错误吧? 有人可以告诉我为什么它没有抛出编译错误?

异常在线程 “主” java.lang.StringIndexOutOfBoundsException:字符串IND 前超出范围:-2 在java.lang.String.substring(未知来源) 在substr11.main(substr11.java:9 )

+1

为什么使用-1? – Gerret

+4

因为编译器不是一个全面的静态分析工具? –

+0

@OliCharlesworth我只想知道它是否有意义。我可能会错误地理解他的问题,我认为他可以使用-1来引导外线 – Gerret

回答

3

编译错误是当编译器不能编译代码(语法错误,缺少符号等..)。

如预期是不是在你的程序中,你传递两个int s到String#substring的情况下,你不会错过任何东西(没有缺课,支架都OK,分号像预想的那样),那么为什么要编译器护理?

你得到一个异常如果代码编译坠毁由于一些异常(如ArrayIndexOutOfBounds)。

1

编译器从不解析或优化到方法调用。即使子字符串操作可能无效且具有硬连线参数,但它并不重要,因为它不会分析整个方法调用。

该调用可能会产生副作用,或者仅在可能包含实例,静态变量甚至库选择的复杂条件集下抛出运行时异常。

编译错误可能包括无效的语法,但不是这样的事情。该方法调用是有效的。也许某个字符串可以将这组参数用于其子字符串方法。编译器不会对该字符串执行复杂的分析。

如果这样做,编译将会花费很长时间,并且会出现许多错误。

0

腾出一些时间来阅读规格JLS#11.2

例外

Java编程语言要求程序包含处理程序检查的异常,这会导致从方法的执行或编译时检查构造函数。对于可能导致的每个检查异常,方法(§8.4.6)或构造函数(§8.8.5)的throws子句必须提及该异常的类或该异常的类的超类之一(§ 11.2.3)。

此编译时检查异常处理程序的存在旨在减少未正确处理的异常数量。在throws子句中命名的checked异常类(§11.1.1)是实现者与方法或构造函数的用户之间的契约的一部分。重写方法的throws子句可能不指定此方法将抛出任何被重写的方法不允许的检查的异常,通过其throws子句抛出(第8.4.8.3节)。

而且hirarchy

java.lang.Object 
    java.lang.Throwable 
    java.lang.Exception 
    java.lang.RuntimeException 
     java.lang.IndexOutOfBoundsException 
     java.lang.StringIndexOutOfBoundsException 

唯一的例外发生在运行时没有在编译时除外。

1

代码中没有编译时错误。对substring()的调用取两个int,这是对substring method的有效调用。

编译器不检查字符串的内容,所以它没有看到这会在运行时抛出异常。

就编译器看来,s变量只被假定为String,其内容没有任何假设。在这种情况下,它被分配了一个常量值,但它可能是无法估量的,比如数据库查询结果或其他东西。这同样适用于函数的参数int

总结一下,在他的回答中指出的六分法,编译器不会对输入执行复杂的分析。开发人员负责对输入进行必要的检查,以避免运行时或检查异常,或相应地捕获它们。

0

不要混淆编译器作业,简而言之就是将代码转换为低级指令和代码执行。在你的情况下,程序应该调用很多子函数来“理解”你的代码中存在逻辑错误。

1

编译器不知道该操作的结果是什么。他知道s.substring()需要2个int参数,他确保该调用是正确的(s.substring(1,-1)必须是int参数)。

0

有人能告诉我为什么它没有抛出编译错误吗?

因为它不是一个编译错误,并有权Java程序员(和他们的经理!)依靠这个不是编译错误!

在另一个世界中,Java语言可能已指定为以要求(或允许)编译器尝试评估substring调用,并将其标记为错误。

但是,在这个世界上,Java编译器只允许为“常量表达式”(如JLS 15.28中指定的那样)做。根据规范,任何包含方法调用的表达式都不是“常量表达式”。因此,在现实中,substring调用必须在运行时进行评估,并且是必须给您一个运行时异常。


那么为什么Java这样设计呢?

您需要问Java设计师...

...但我认为它是两件事的组合:

  • Java 1.0语言必须提前发布,否则它将错过市场机会。

  • 然后对向后兼容性有一个首要的要求......以便随着语言的发展,旧的Java程序将继续工作。