1/0是合法的Java表达式吗? [英] Is 1/0 a legal Java expression?

查看:256
本文介绍了1/0是合法的Java表达式吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下在我的Eclipse中编译正常:

  final int j = 1/0; 
//编译好!!!
//抛出ArithmeticException:/在运行时为零

Java防止了许多哑巴代码从第一个位置开始编译(例如Fiveinstanceof Number 不编译!),所以事实上这甚至没有产生警告对我来说非常惊讶。当您考虑允许在编译时优化常量表达式这一事实时,阴谋会加深:

  public class Div0 {
public static void main(String [] args){
final int i = 2 + 3;
final int j = 1/0;
final int k = 9/2;
}
}

在Eclipse中编译,上面的代码片段生成以下字节码( javap -c Div0

 编译自Div0.java 
public class Div0 extends java.lang.Object {
public Div0();
代码:
0:aload_0
1:invokespecial#8; //方法java / lang / Object。< init>:()V
4:return

public static void main(java.lang.String []);
代码:
0:iconst_5
1:istore_1 //i = 5;
2:iconst_1
3:iconst_0
4:idiv
5:istore_2 //j = 1/0;
6:iconst_4
7:istore_3 //k = 4;
8:返回

}

如您所见, i k 赋值被优化为编译时常量,但除以 0 (必须在编译时可以检测到)只是按原样编译。



javac 1.6.0_17 表现得更奇怪,无声编译但是将作业完全删除 i k 字节码(可能是因为它确定它们没有在任何地方使用),但保留 1/0 完整(因为删除它会导致完全不同的程序语义)。 / p>

所以问题是:




  • 1 / 0 实际上是一个合法的Java表达式,应该随时随地编译?


    • JLS对此有何评价?


  • 如果这样是合法的,有充分的理由吗?


    • 这有什么用呢?



解决方案


1/0 实际上是一个合法的Java表达式应该随时随地编译吗?


是。


JLS是什么怎么说呢?


没有什么特别的......除了说除以零将导致运行时异常。但是,JLS在以下定义中承认运行时异常的可能性:


编译时常量表达式是表示值的表达式原始类型或字符串不突然完成,仅使用以下内容组成:...


(重点补充。)所以以下内容不会编译:

  switch(i){
case 1 :
case 1 + 1:
case 1/0://编译错误。
}




如果这是合法的,是否有好处原因呢?


好问题。我想这是一种抛出 ArithmeticException 的方法,尽管这不是一个合理的理由。以这种方式指定Java的一个更可能的原因是为了避免JLS和编译器中不必要的复杂性来处理很少会让人咬人的边缘情况。



但是这个一切都在旁边。事实是 1/0 是有效的Java代码,并且没有Java编译器应该将此标记为编译错误。 (如果有一个编译器开关将其关闭,那么Java编译器发出警告是合理的。)


The following compiles fine in my Eclipse:

final int j = 1/0;
// compiles fine!!!
// throws ArithmeticException: / by zero at run-time

Java prevents many "dumb code" from even compiling in the first place (e.g. "Five" instanceof Number doesn't compile!), so the fact this didn't even generate as much as a warning was very surprising to me. The intrigue deepens when you consider the fact that constant expressions are allowed to be optimized at compile time:

public class Div0 {
    public static void main(String[] args) {
        final int i = 2+3;
        final int j = 1/0;
        final int k = 9/2;
    }
}

Compiled in Eclipse, the above snippet generates the following bytecode (javap -c Div0)

Compiled from "Div0.java"
public class Div0 extends java.lang.Object{
public Div0();
  Code:
   0:   aload_0
   1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   iconst_5
   1:   istore_1      // "i = 5;"
   2:   iconst_1
   3:   iconst_0
   4:   idiv
   5:   istore_2      // "j = 1/0;"
   6:   iconst_4
   7:   istore_3      // "k = 4;"
   8:   return

}

As you can see, the i and k assignments are optimized as compile-time constants, but the division by 0 (which must've been detectable at compile-time) is simply compiled as is.

javac 1.6.0_17 behaves even more strangely, compiling silently but excising the assignments to i and k completely out of the bytecode (probably because it determined that they're not used anywhere) but leaving the 1/0 intact (since removing it would cause an entirely different program semantics).

So the questions are:

  • Is 1/0 actually a legal Java expression that should compile anytime anywhere?
    • What does JLS say about it?
  • If this is legal, is there a good reason for it?
    • What good could this possibly serve?

解决方案

Is 1/0 actually a legal Java expression that should compile anytime anywhere?

Yes.

What does JLS say about it?

Nothing specific ... apart from saying that division by zero will result in a runtime exception. However, the JLS acknowledges that possibility of runtime exceptions in the following definition:

"A compile-time constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following: ..."

(Emphasis added.) So the following would NOT compile:

switch(i) {
    case 1:
    case 1 + 1: 
    case 1 / 0:  // compilation error.
}

If this is legal, is there a good reason for it?

Good question. I suppose that it is a way to throw ArithmeticException though that is hardly a plausible reason. A more likely reason for specifying Java this way is to avoid unnecessary complexity in the JLS and compilers to deal with an edge case that is rarely going to bite people.

But this is all by the by. The fact is that 1/0 is valid Java code, and no Java compiler should ever flag this as a compilation error. (It would be reasonable for a Java compiler to issue a warning, provided that there was a compiler switch to turn it off.)

这篇关于1/0是合法的Java表达式吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆