/**
* 百度面试题 http://student.csdn.net/mcd/topic/235300/753730
* 依序遍历0到100闭区间内所有的正整数,如果该数字能被3整除,则输出该数字及‘*’标记;如果该数字能被5整除,则输出该数字及‘#’标记;
* 如果该数字既能被3整除又能被5整除,则输出该数字及‘*#’标记。
*/
对算法没有什么研究, 只是觉得好的算法能给程序带来更快的速度, 所以我下面代码的重点不是算法,而是哪个运行耗时最少:
public class Test {
StringBuffer sBuffer;
StringBuilder sBuilder;
public static void main(String[] args) {
long start = System.nanoTime();
foo();
long end = System.nanoTime();
System.out.println("--------1-------");
long start1 = System.nanoTime();
Test test = new Test();
test.sBuffer = new StringBuffer();
test.foo1();
System.out.println(test.sBuffer);
long end1 = System.nanoTime();
System.out.println("--------2-------");
long start2 = System.nanoTime();
Test test2 = new Test();
test2.sBuilder = new StringBuilder();
test2.foo2();
System.out.println(test2.sBuilder);
long end2 = System.nanoTime();
System.out.println("--------3-------");
long start3 = System.nanoTime();
new Test().foo3();
long end3 = System.nanoTime();
System.out.println("--------4-------");
long start4 = System.nanoTime();
Test test4 = new Test();
test4.sBuilder = new StringBuilder();
test4.foo4();
System.out.println(test4.sBuilder);
long end4 = System.nanoTime();
long start5 = System.nanoTime();
Test test5 = new Test();
test5.sBuilder = new StringBuilder();
test5.foo5();
System.out.println(test5.sBuilder);
long end5 = System.nanoTime();
System.out.println(end - start);
System.out.println(end1 - start1);
System.out.println(end2 - start2);
System.out.println(end3 - start3);
System.out.println(end4 - start4);
System.out.println(end5 - start5);
}
/**
* 方法一:直接使用+ 拼接
*
* @author Administrator
* @date 2014年4月24日
*/
private static void foo() {
for (int i = 1; i <= 100; i++) {
if (i % 3 == 0 && i % 5 == 0) {
System.out.println(i + "*#");
} else if (i % 5 == 0) {
System.out.println(i + "#");
} else if (i % 3 == 0) {
System.out.println(i + "*");
}
}
}
/**
* 方法二:采用StringBuffer
*
* @author Administrator
* @date 2014年4月24日
*/
private void foo1() {
for (int i = 1; i <= 100; i++) {
if (i % 3 == 0 && i % 5 == 0) {
putBuffer(i, "*#");
} else if (i % 5 == 0) {
putBuffer(i, "#");
} else if (i % 3 == 0) {
putBuffer(i, "*");
}
}
}
/**
* 方法三:采用StringBuilder
*
* @author Administrator
* @date 2014年4月24日
*/
private void foo2() {
for (int i = 1; i <= 100; i++) {
if (i % 3 == 0 && i % 5 == 0) {
putBuilder(i, "*#");
} else if (i % 5 == 0) {
putBuilder(i, "#");
} else if (i % 3 == 0) {
putBuilder(i, "*");
}
}
}
/**
* 网友参考答案
*/
private void foo3() {
final int COUNT = 100; // 为什么是final , 使用final的好处是什么?
boolean isMod3;
boolean isMod5;
for (int i = 1; i <= COUNT; i++) {
isMod3 = i % 3 == 0;
isMod5 = i % 5 == 0;
if (isMod3 && isMod5) {
System.out.println(i + " *#");
} else if (isMod3) {
System.out.println(i + " *");
} else if (isMod5) {
System.out.println(i + " #");
}
}
}
/**
* 更改参考答案
*/
private void foo4() {
final int COUNT = 100; // 为什么是final , 使用final的好处是什么?
boolean isMod3;
boolean isMod5;
for (int i = 1; i <= COUNT; i++) {
isMod3 = i % 3 == 0;
isMod5 = i % 5 == 0;
if (isMod3 && isMod5) {
putBuilder(i, "*#");
} else if (isMod3) {
putBuilder(i, "*");
} else if (isMod5) {
putBuilder(i, "#");
}
}
}
/**
* 更改网友答案
*/
private void foo5() {
int COUNT = 100; // 为什么是final , 使用final的好处是什么?
boolean isMod3;
boolean isMod5;
for (int i = 1; i <= COUNT; i++) {
isMod3 = i % 3 == 0; // isMod3 = (i%3==0)
isMod5 = i % 5 == 0;
if (isMod3 && isMod5) {
putBuilder(i, "*#");
} else if (isMod3) {
putBuilder(i, "*");
} else if (isMod5) {
putBuilder(i, "#");
}
}
}
/**
* 添加符合要求的数字和所对应的字符
*
* @param i
* 数字
* @param s
* 字符
* @author Administrator
* @date 2014年4月24日
*/
private void putBuilder(int i, String s) {
sBuilder.append(i);
sBuilder.append(s);
sBuilder.append("\n");
}
private void putBuffer(int i, String s) {
sBuffer.append(i);
sBuffer.append(s);
sBuffer.append("\n");
}
}
程序运行时间:
/*
* 耗时:
* 1211687 直接拼接
* 153947 StringBuffer
* 103593 StringBuilder
* 1105859 参考
* 131818 改参考后
* 108725 不加final
*/
单看,100次循环的耗时, 可以看出 , StringBuilder 耗时是最少, 加final的反而耗时更多.
将循环次数, 该为100000,多次运行后各个方法所耗时为:
// 291248482
// 27186869
// 37310223
// 238034804
// 57009133
// 135859617
// 291248482 //直接
// 27186869 //StringBuffer
// 37310223 //StringBuilder
// 238034804 //..
// 57009133 //StringBuilder+..+final
// 135859617 //StringBuilder+ ..
// 289988355
// 94520451
// 37578349
// 203889493
// 48452840
// 133518969
// 294954135
// 27723121
// 143139427
// 272538045
// 67523450
// 135150816
// 280107789
// 20859612
// 135050429
// 314615520
// 47390279
// 137197360
// 294913403
// 37562313
// 133788698
// 286650573
// 55538290
// 138061072
...
可以得出:
StringBuffer 和StringBuilder 耗时比较少, 由于StringBuilder是线程不安全的,理论上是要比Stringbuffer更快;
使用+ 拼接的是特别耗时的, final 在循环次数增多以后,其对于不加final来说,效果是明显的.
同样,采用直接拼接字符, 没优化算法之前的方法一要比优化算法后的方法四耗时明显.
相关权威理论,可以从<<Java编程思想>>P506 Stirng vs StringBuffer获得
PS :
性能优化无末日, 我们能做的很多 -- Tx某工程师