在评估一些非常具体的 if 条件时,我遇到了一些非常奇怪的性能行为。
基本上,我发现我可以构造两个条件 a 和 b,这样即使总是 false 也if(a)
快 10 倍,这似乎与 Java 应该对条件进行惰性求值这一事实直接冲突。if(a && b)
a
这种情况发生在我必须a
成为someDate.after(startdate)
和b
成为someDate.before(enddate)
——即相当标准的范围条件时。
下面我附上了我用来显示这个特定问题的代码。我已经在带有 Java 7 的 Windows 7 上运行了代码,我的一位同事已经在带有 Java 6,7 和 8 的 Windows 7 上运行了它——结果都一样。
谁能解释为什么会发生这种情况?
import java.util.Date;
public class DateWeirdness {
public static void main(String[] args) {
Date start = new Date();
System.out.println("if(a) - a always false");
System.out.println(timeBasic(2000000000, start, start.getTime() - 4000000000L));
start = new Date();
System.out.println("if(a && b) - a always false, a and b both date method");
System.out.println(timeAdv(2000000000, start, start.getTime() - 4000000000L, new Date()));
start = new Date();
System.out.println("if(a && b) - a always false, b is condition on longs not date");
System.out.println(timeAdv2(2000000000, start, start.getTime() - 4000000000L, new Date().getTime()));
start = new Date();
System.out.println("if(a) - a always false - condition on long");
System.out.println(timeBasicL(2000000000, start.getTime(), start.getTime() - 4000000000L));
start = new Date();
System.out.println("if(a && b) - a always false, a and and b both conditions on long");
System.out.println(timeAdvL(2000000000, start.getTime(), start.getTime() - 4000000000L, new Date().getTime()));
start = new Date();
System.out.println("if(a && b) - a always false, b always true");
System.out.println(timeAdv(2000000000, start, start.getTime() - 4000000000L, new Date()));
start = new Date();
System.out.println("if(a && b) - both true");
System.out.println(timeAdv(2000000000, start, start.getTime() + 1, new Date(start.getTime() + 4000000000L)));
start = new Date();
System.out.println("if(a && b) - a always true, b always false");
System.out.println(timeAdv(2000000000, start, new Date(start.getTime() + 4000000001L).getTime(), new Date(start.getTime() + 4000000000L)));
}
private static int timeBasic(int size, Date start, long l) {
long begin = System.currentTimeMillis();
int c = 0;
for (int i = 0; i < size; i++) {
Date date = new Date(l++);
if (start.before(date)) {
c++;
}
}
System.out.println(System.currentTimeMillis() - begin);
return c;
}
private static int timeAdv(int size, Date start, long l, Date end) {
long begin = System.currentTimeMillis();
int c = 0;
for (int i = 0; i < size; i++) {
Date date = new Date(l++);
if (start.before(date) && end.after(date)) {
c++;
}
}
System.out.println(System.currentTimeMillis() - begin);
return c;
}
private static int timeAdv2(int size, Date start, long l, long end) {
long begin = System.currentTimeMillis();
int c = 0;
for (int i = 0; i < size; i++) {
Date date = new Date(l++);
if (start.before(date) && end > l) {
c++;
}
}
System.out.println(System.currentTimeMillis() - begin);
return c;
}
private static int timeBasicL(int size, long start, long l) {
long begin = System.currentTimeMillis();
int c = 0;
for (int i = 0; i < size; i++) {
l++;
if (start < l) {
c++;
}
}
System.out.println(System.currentTimeMillis() - begin);
return c;
}
private static int timeAdvL(int size, long start, long l, long end) {
long begin = System.currentTimeMillis();
int c = 0;
for (int i = 0; i < size; i++) {
l++;
if (start < l && end > l) {
c++;
}
}
System.out.println(System.currentTimeMillis() - begin);
return c;
}
}
在本地运行它时,我得到以下输出。有趣的测试是前三个测试。640
是以毫秒为单位的doing的性能if(a)
,7079
是doing 的性能if(a && b)
,wherea
和b
are 如上所述。710
是做if(a && b)
where b
is的表现someDateAsLong < endDateAsLong
。
if(a) - a always false
640
0
if(a && b) - a always false, a and b both date method
7079
0
if(a && b) - a always false, b is condition on longs not date
710
0
if(a) - a always false - condition on long
639
0
if(a && b) - a always false, a and and b both conditions on long
708
0
if(a && b) - a always false, b always true
6873
0
if(a && b) - both true
11995
2000000000
if(a && b) - a always true, b always false
13746
0