java中无限循环的方法_Java中的无限循环

Java中的无限循环

在Java中查看下面的无限while循环。 它会导致它下面的语句编译时错误。

while(true) { System.out.println("inside while"); } System.out.println("while terminated"); //Unreachable statement - compiler-error.

以下相同的无限while循环,但工作正常,不会发出任何错误,我只是用布尔variablesreplace条件。

boolean b=true; while(b) { System.out.println("inside while"); } System.out.println("while terminated"); //No error here.

在第二种情况下,循环后面的语句显然是不可达的,因为布尔variablesb是真的,编译器根本不会抱怨。 为什么?

编辑:下面的版本while明显陷入死循环中,但是对于它下面的语句没有编译器错误,即使循环中的if条件总是false ,因此循环永远不会返回,并且可以由编译器本身就是编译器。

while(true) { if(false) { break; } System.out.println("inside while"); } System.out.println("while terminated"); //No error here.

while(true) { if(false) { //if true then also return; //Replacing return with break fixes the following error. } System.out.println("inside while"); } System.out.println("while terminated"); //Compiler-error - unreachable statement.

while(true) { if(true) { System.out.println("inside if"); return; } System.out.println("inside while"); //No error here. } System.out.println("while terminated"); //Compiler-error - unreachable statement.

编辑:同样的事情, if和while 。

if(false) { System.out.println("inside if"); //No error here. }

while(false) { System.out.println("inside while"); // Compiler's complain - unreachable statement. }

while(true) { if(true) { System.out.println("inside if"); break; } System.out.println("inside while"); //No error here. }

以下版本也陷入了无限循环。

while(true) { try { System.out.println("inside while"); return; //Replacing return with break makes no difference here. } finally { continue; } }

这是因为即使return语句在try块本身之前遇到finally块, finally块也总是被执行。

编译器可以很容易和明确地certificate第一个expression式总是导致一个无限循环,但是对于第二个expression式来说并不那么容易。 在你的玩具的例子很简单,但如果:

variables的内容是从文件中读取的?

该variables不是本地的,可以被另一个线程修改?

variables依赖于一些用户input?

编译器显然不检查你的简单情况,因为它完全放弃了这条路。 为什么? 因为规范要严格得多 。 参见14.21节 :

(顺便说一下,当variables被声明为final时,我的编译器会报错。)

根据规格 ,以下是关于发言的说法。

如果满足以下至less一个条件,while语句可以正常完成:

while语句是可达的,条件expression式不是一个值为true的常量expression式。

有一个可访问的break语句退出while语句。\

因此,如果while条件是一个具有真值的常量,或者在while语句中有break语句,编译器只会说while后面的代码是不可访问的。 在第二种情况下,由于b的值不是一个常数,所以它不考虑它后面的代码是不可达的。 这个链接背后有更多的信息,让你知道什么是什么,什么是不被认为是不可达的。

因为真是恒定的,b可以在循环中改变。

因为分析variables状态很难,所以编译器几乎已经放弃了,让你做你想做的事情。 另外,Java语言规范对如何允许编译器检测不可达代码有明确的规则。

欺骗编译器有很多方法 – 另一个常见的例子是

public void test() { return; System.out.println("Hello"); }

这是行不通的,因为编译器会意识到该地区是不可能的。 相反,你可以这样做

public void test() { if (2 > 1) return; System.out.println("Hello"); }

这是可行的,因为编译器不能意识到expression式永远不会是错误的。

后者是不可达的。 布尔值b仍然有可能被修改为false,导致结束条件的循环内的某个地方。

我的猜测是variables“b”有可能改变它的值,所以编译器认为System.out.println("while terminated"); 可以达到。

编译器并不完美 – 也不应该这样做

编译器的责任是确认语法 – 不是要确认执行。 编译器可以最终捕获和防止强types语言中的许多运行时问题 – 但是它们不能捕获所有这些错误。

实际的解决scheme是使用unit testing的电池来补充编译器的检查,或者使用面向对象的组件来实现已知稳健的逻辑,而不是依靠原始variables和停止条件。

强大的打字和OO:提高编译器的功效

有些错误本质上是语法的 – 在Java中,强types使得运行时exception可以被捕获。 但是,通过使用更好的types,可以帮助编译器执行更好的逻辑。

如果您希望编译器更有效地执行逻辑,那么在Java中,解决scheme就是构build可强制执行此类逻辑的强健的必需对象,并使用这些对象构build应用程序,而不是构build原语。

一个经典的例子是迭代器模式的使用,加上Java的foreach循环,这个构造对于你所说明的缺陷types的影响要小于一个简单的while循环。

编译器不够复杂,无法运行b可能包含的值(尽pipe您只分配一次)。 第一个例子很容易让编译器看到它将是一个无限循环,因为条件是不可变的。

我很惊讶你的编译器拒绝编译第一个案例。 这对我来说似乎很奇怪。

但是第二种情况没有针对第一种情况进行优化,因为(a)另一个线程可能更新b的值(b)被调用的函数可能会修改b的值作为副作用。

其实我觉得没有人知道它是正确的(至less不是在原来的提问者的意义上)。 OQ不断提及:

正确,但不相关,因为b在循环中没有被改变

但是没关系,因为最后一行是可达的。 如果你把这个代码编译成一个类文件并把类文件交给其他人(比如库),那么他们可以把编译后的类与通过reflection修改“b”的代码联系起来,退出循环并导致最后一个行执行。

任何不是常量的variables(或最终编译为使用位置的常量)都是如此 – 如果使用final来重新编译类,而不是引用它的类,则引用奇怪的错误,引用class级仍旧保持原来的价值,没有任何错误)

我已经使用了reflection的能力来修改另一个类的非最终私有variables,以便在购买的库中修改一个类 – 修复一个bug,以便在我们等待来自供应商的官方补丁时继续开发。

顺便说一下,这可能实际上不是现在的工作 – 虽然我以前做过,但有一个机会,这样一个小的循环将caching在CPUcaching中,并且由于该variables不标记为volatile,caching的代码可能永远不会拿起新的价值。 我从来没有见过这样的行动,但我相信这在理论上是正确的。

这只是因为编译器不要太多的宝宝坐着工作,尽pipe这是可能的。

所示的例子对于编译器检测无限循环是简单而合理的。 但是我们如何插入1000行代码,而与variablesb没有任何关系呢? 那么这些陈述如何都是b = true; ? 编译器肯定可以评估结果,并告诉你最终在while循环中是真的,但编译一个真正的项目会有多慢?

PS,皮棉工具绝对应该为你做。

从编译器的angular度来看, while(b)可能在某处变成false。 编译器只是不麻烦检查。

为了有趣的尝试while(1 < 2) , for(int i = 0; i < 1; i--)等

在运行时计算expression式,所以当用一个布尔variablesreplace标量值“true”时,您将标量值更改为布尔expression式,因此编译器无法在编译时知道它。

如果编译器可以确定地确定布尔值在运行时将评估为true ,则会抛出该错误。 编译器假定你声明的variables是可以改变的(虽然我们在这里知道它不会)。

为了强调这个事实,如果variables在Java中被声明为final ,那么大多数编译器都会抛出相同的错误,就像replace值一样。 这是因为variables是在编译时定义的(并且不能在运行时更改),因此编译器可以确定在运行时expression式的计算结果为true 。

第一个Statement总是导致一个无限循环,因为我们已经在while循环的条件中指定了一个常量,而在第二个情况下,编译器假设在循环内部有可能改变b的值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java,由于浮点数的精度问题,可能会出现无限循环小数。对于这种情况,可以使用BigDecimal类来处理。 BigDecimal类可以表示任意精度的十进制数,它可以处理大于64位的整数和小数。在使用BigDecimal类时,需要注意以下几点: 1. 使用BigDecimal类时,应该使用其构造方法来初始化BigDecimal对象,而不是使用double类型的值来初始化。 例如: ``` BigDecimal bd = new BigDecimal("0.1"); ``` 2. 在进行浮点数运算时,应该使用BigDecimal类提供的方法,而不是使用double类型的运算符。 例如: ``` BigDecimal a = new BigDecimal("0.1"); BigDecimal b = new BigDecimal("0.2"); BigDecimal c = a.add(b); ``` 3. 在比较两个BigDecimal对象的值时,应该使用compareTo()方法,而不是使用等于(==)或不等于(!=)运算符。 例如: ``` BigDecimal a = new BigDecimal("0.1"); BigDecimal b = new BigDecimal("0.2"); if (a.compareTo(b) < 0) { System.out.println("a < b"); } else if (a.compareTo(b) > 0) { System.out.println("a > b"); } else { System.out.println("a = b"); } ``` 关于java无限循环小数判定问题,可以通过以下代码来解决: ``` public static boolean isRepeatingDecimal(BigDecimal num) { BigDecimal[] arr = num.divideAndRemainder(BigDecimal.ONE); BigDecimal decimalPart = arr[1]; String decimalStr = decimalPart.toString().substring(2); // 去掉小数点和整数部分 if (decimalStr.length() < 2) { return false; // 小数部分长度小于2,不可能循环 } int halfLength = decimalStr.length() / 2; for (int i = 1; i <= halfLength; i++) { String str = decimalStr.substring(0, i); if (decimalStr.matches("^(" + str + ")+(.*)" + str + "$")) { return true; // 存在循环节 } } return false; // 不存在循环节 } ``` 该方法接收一个BigDecimal对象,判断其是否为无限循环小数,返回true或false。 以上是关于Java处理无限循环小数的基础知识和方法介绍,希望能对你有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值