【java解惑】&和&&、|和||使用

如下所示代码:

public class Example042 {

	public static void main(String[] args) {
		int[][] tests = { { 6, 5, 4, 3, 2, 1 }, { 1, 2 }, { 1, 2, 3 },
				{ 1, 2, 3, 4 }, { 1 } };
		System.out.println("func1 out : " + func1(tests));
	}

	private static int func1(int[][] tests) {
		int successCount = 0;
		try {
			int i = 0;
			while (true) {
				if (thirdElementIsThree1(tests[i++])) {
					successCount++;
				}
			}
		} catch (ArrayIndexOutOfBoundsException e) {
			// No more tests to process
		}
		return successCount;
	}

	private static boolean thirdElementIsThree1(int[] a) {
		return a.length >= 3 & a[2] == 3;
	}
}

输出结果:

func1 out : 0

结果分析:

上述代码有两个很严重的BUG。第一个BUG是使用了可能产生异常的条件做循环控制;第二个是错误使用“&”和“&&”。

使用可能产生异常的条件做循环控制不仅难以阅读,而且运行速度还非常地慢。不要使用异常来进行循环控制,应该只为异常条件而使用异常。可以使用如下代码来重写func1:

private static int func1(int[][] tests) {
		int successCount = 0;
		try {
			for (int[] test : tests) {
				if (thirdElementIsThree1(test)) {
					successCount++;
				}
			}
		} catch (ArrayIndexOutOfBoundsException e) {
			e.printStackTrace();
		}
		return successCount;
	}

修正后的代码输出结果依然存在问题,而且会捕获到数组越界的异常。问题出现在thirdElementIsThree1方法上。这个方法错误的使用了“&”,本来这里是需要使用“&&”的,如下:

private static boolean thirdElementIsThree1(int[] a) {
		return a.length >= 3 && a[2] == 3;
}

为什么使用“&”会抛出异常呢?在func1中导致结果输出为0呢?& 操作符有其他的含义。除了常见的被当作整型操作数的位 AND 操作符之外,当被用于布尔操作数时,它的功能被重载为逻辑 AND 操作符。这个操作符与更经常被使用的条件 AND 操作符有所不同,& 操作符总是要计算它的两个操作数,而 && 操作符在其左边的操作数被计算为 false 时,就不再计算右边的操作数了。因此,thirdElementIsThree1 方法总是要试图访问其数组参数的第三个元素,即使该数组参数的元素不足 3 个也是如此。

同样的,还有一个逻辑 OR 操作符(| ) 也伴随着条件 OR 操作符(|| ), |  操作符总是要计算它的两个操作数,而 ||  操作符在其左边的操作数被计算为true 时,就不再计算右边的操作数了。



注:本【java解惑】系列均是博主阅读《java解惑》原书后将原书上的讲解和例子部分改编然后写成博文进行发布的。所有例子均亲自测试通过并共享在github上。通过这些例子激励自己惠及他人。同时本系列所有博文会同步发布在博主个人微信公众号搜索“爱题猿”或者“ape_it”方便大家阅读。如果文中有任何侵犯原作者权利的内容请及时告知博主以便及时删除如果读者对文中的内容有异议或者问题欢迎通过博客留言或者微信公众号留言等方式共同探讨。

源代码地址https://github.com/rocwinger/java-disabuse

【java解惑】&和&&、|和||使用

时间: 2025-01-07 15:30:48

【java解惑】&和&&、|和||使用的相关文章

【java解惑】前缀自增自减和后缀自增自减问题

    如下代码: public class Example025 { public static void main(String[] args) { int ape = 100; int it = 100; int ape_it = 100; for (int i = 0; i < 100; i++) { ape--; it = it--; ape_it = --ape_it; } System.out.println("ape = " + ape); System.out.

《Java 解惑》笔记(一)

<Java 解惑>里都是一些编程时容易忽略的细节,却也蛮有意思的,所以将里面的内容稍作整理,简略地概括一下: 1.奇数性 在编程的时候经常会遇到要判断传进来的参数是否为奇数,而且容易惯性地认为判断余数是否为1即可,如下代码: public static boolean isOdd ( int i ) { return i % 2 == 1 } 这段程序在四分之一的时间里返回的都是错误的答案 因为在所有的 int 数值中,有一半都是负数,而 isOdd 方法对于对所有负奇数的判断都会失败.在任何

java解惑之常常忘记的事

java解惑之常常忘记的事 2012-10-17 18:38:57|  分类: JAVA |  标签:基础知识  软件开发  |举报|字号 订阅 针对刚接触java的菜鸟来说,java基础知识都是我们必须认真学习的,但是在工作过几年时间的老鸟来说,有时候也会对java的基础知识产生疑问,对于这种不确定,并且很容易混淆的知识点,java解惑已经为大家进行了很好的总结,现在借用一个作者的总结,进行一下罗列,希望能对你有所帮助. 1. 奇偶判断 不要使用 i % 2 == 1 来判断是否是奇数,因为i

Java解惑七:更多类之谜

谜题66 继承的问题. 对于实例方法:命名相同时,子类会覆写父类的方法,且访问权限至少和父类一样大. 对于域:命名相同时,子类会隐藏父类的域,且访问权限任意. 谜题67 不要重用库中的类名. 谜题68 命名的问题. 类名应该以大写字母开头,形式为:MixedCase. 变量以小写字母开头,形式为:mixedCase. 常量以大写字母开头,形式为:MIXED_CASE. 单个大写字母,只能用于类型参数,形式为:Map<K, V>. 包名应该都是小写,形式为:lower.case. 当一个变量和一

《Java解惑》读书笔记

 摘选自<Java解惑>一书,之前整理了部分,一直没看完,最近为了督促自己每天读点这本书,决定一天至少更新一个谜题的内容,欢迎讨论. 欢迎关注技术博客http://blog.sina.com.cn/u/1822488043 Java解惑读书笔记 谜题1:奇数性 取余操作的定义: ( a / b ) * b + ( a % b ) = a 其中(a/b)是java运算的结果,也就是a/b是一个整数,比如3/2=1. 所以当取余操作返回一个非零结果的时候,它与左操作数具有相同符号. 请测试你的

【java解惑】重载构造函数

如下所示代码: public class Example046 { private Example046(Object o) { System.out.println("Object"); } private Example046(double[] dArray) {//2 System.out.println("double array"); } private Example046(String str) {//3 System.out.println(&quo

【java解惑】移位运算符规则

    如下代码: public class Example027 { public static void main(String[] args) { int i = 0; while (-1 << 32 != 0) { i++; } System.out.println(i); } }     结果说明:     将上述程序放到eclipse中,在输出行会有提示"Unreachable code".也就是while循环是死循环无法退出.     结果分析:     Ja

java解惑

谜题45:令人疲惫不堪的测验 收获: (1)递归调用的先序便利二叉树,以后在理解递归时可以做出书上所示的递归二叉树.这个图的好处是,指出了递归的深度+递归叶子层+调用的顺序(通过在每条线加上调用序号). (2)JVM的栈深度默认是1024:这也就导致本题的线序遍历二叉树边数过多,永远不会抛出stackoverflow的exception. (3)如何设置JVM,一开始我都不知道,原来是用java命令. 相应参考资料: http://hi.baidu.com/sdausea/item/f4671b

Java解惑五:类之谜

本文是依据JAVA解惑这本书,做的笔记.电子书见:http://download.csdn.net/detail/u010378705/7527721 谜题46 函数重载的问题. JAVA重载解析过程:1. 选取全部可用的方法或者构造器:2. 从过程1中选取的方法或构造器中选择最精确的. 一般而言:能够强制要求编译器选择一个精确的重载版本号,将实參转型为形參所声明的类型. 谜题47 继承中静态域的问题. 静态域由声明它的类及其全部子类共享. 假设须要让每个子类都具有某个域的单独拷贝,必须在每个子

Java解惑八:更多库之谜

本文是根据JAVA解惑这本书,做的笔记. 电子书见:http://download.csdn.net/detail/u010378705/7527721 谜题76 将线程的启动方法start(),写成了run(); PS:管程(monitor)锁有待进一步理解. 谜题77 线程中锁的问题. 理解不深刻. 谜题78 反射会造成访问其他包中的非公共类型的成员,引起运行期异常. 谜题79 遮蔽:Thread.sleep()方法遮蔽了自定的方法. 谜题80 反射:如何实例化非静态内部类以及静态内部类.