JAVA优化
代码优化
判定奇数
public static void main(String[] args) {
System.out.println(judgeOddNumber(-5));
}
/**
* 判定是否为奇数
* @param i
* @return
*/
private static boolean judgeOddNumber(int i) {
return i % 2 == 1;
}
因为在方法中i%2等于-1而不是1,计算满足以下恒等式:
(a / b) * b + (a % b) == a
所以方法改成如下:
/**
* 判定是否为奇数
* @param i
* @return
*/
private static boolean judgeOddNumber(int i) {
return i % 2 != 0;
}
或者更好的方式使用位运算符替代会更好
/**
* 判定是否为奇数
* @param i
* @return
*/
private static boolean judgeOddNumber(int i) {
return (i & 1) != 0;
}
数据计算
public static void main(String[] args) {
System.out.println(2.00-1.10);
}
执行结果如下:
D:\Java\jdk1.8.0_131\bin\java.exe ...
0.8999999999999999
问题在于1.1不能精确的表示为一个double,因此表示成一个最接近它的double值。
目前有些人使用以下方式解决输出正确方式:
public static void main(String[] args) {
double a = 2.00;
double b = 1.10;
System.out.println(String.format("%.1f",a-b));
}
结果显示0.9。但是输出结果是正确结果,但并不是对底层问题的通用解决方案。
数据计算尽量使用BigDecimal。如下:
public static void main(String[] args) {
BigDecimal a = new BigDecimal(2.00+"");
BigDecimal b = new BigDecimal(1.10+"");
System.out.println(a.subtract(b));
}
结果:0.9
可能很好奇为什么数字后面要加空字符串,因为我们在开发的过程中应该避免使用BigDecimal(double)。因为它会使用参数的精确值创建一个实例。
public static void main(String[] args) {
BigDecimal a = new BigDecimal(2.00);
BigDecimal b = new BigDecimal(1.10);
System.out.println(a.subtract(b));
}
结果:0.899999999999999911182158029987476766109466552734375
long类型计算
public static void main(String[] args) {
long a = 24 * 60 * 60 * 1000 * 1000;
long b = 24 * 60 * 60 * 1000;
System.out.println(a/b);
}
结果:5
结算结果为什么是5呢?显然应该是1000的。但是因为右侧的计算都是通过int计算的,计算结束后结果才被提升为long类型
public static void main(String[] args) {
int a = 24 * 60 * 60 * 1000 * 1000;
long a1 = 24 * 60 * 60 * 1000 * 1000L;
System.out.println("a的值:" + a);
System.out.println("a1的值:" + a1);
long c = a;
long b = 24 * 60 * 60 * 1000;
System.out.println(c/b);
}
结果:
a的值:500654080
a1的值:86400000000
5
值小了约200倍。**所以在操作很大的数字时,需要提防溢出。**所以正确写法应该是
public static void main(String[] args) {
long a = 24L * 60 * 60 * 1000 * 1000;
long b = 24L * 60 * 60 * 1000;
System.out.println(a/b);
}
千万不要写成上一个代码,把最后一个数转成long运算,代码是从左到右计算的,有可能还没到右边最后一步又溢出了。
同时,我们在使用的过程中要比秒小写L(l)
public static void main(String[] args) {
System.out.println(12345+5432l);
}
结果:17777
并不是66666。所以平时需要注意1和l的区别。
混合类型计算
public static void main(String[] args) {
char x = 'X';
int t = 0;
System.out.println(false?t:x);
}
结果:88
三目表达式核心有以下三点:
- 如果第二个和第三个操作数是相同的类型,那么就是条件表达式类型。
- 如果一个操作数是T(char,byte,short),另一个是int,值类型可以用T表示,那么三目表达式的类型就是T。
- 否则就对操作数进行二进制数字提升
public static void main(String[] args) {
short x = 0;
int t = 123456;
x+=t;
System.out.println(x);
}
结果:-7616。
int类型对于short来说数值太高了,所以把int数值的高两位截掉了。
所以尽量不使用混合类型计算,避免数据转型导致的错误
注释问题
/**
* 第一个java程序
* package from: C:\Test\unit1
* @param args
*/
public static void main(String[] args) {
System.out.println("Hello World");
}
结果:java: 非法的 Unicode 转义
(\u)表示一个Unicode转义字符的开始。所以不应该将windows的文件名置于代码当中,哪怕它是注释。
标号
/**
* 第一个java程序
* @param args
*/
public static void main(String[] args) {
System.out.print("Hello ");
http://www.baidu.com;
System.out.println("World");
}
结果:Hello World
标号实际上很常用,但是很多人不知道
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
ii:
for (int j = 0; j < 4; j++) {
if (j == 1) {
break ii;
}
jj:
for (int k = 0; k < 5; k++) {
for (int l = 0; l < 6; l++) {
System.out.println("i="+i+",j="+j+",k="+k+",l="+l);
if (l == 2) {
break jj;
}
}
}
}
}
}
结果:
i=0,j=0,k=0,l=0
i=0,j=0,k=0,l=1
i=0,j=0,k=0,l=2
i=1,j=0,k=0,l=0
i=1,j=0,k=0,l=1
i=1,j=0,k=0,l=2
i=2,j=0,k=0,l=0
i=2,j=0,k=0,l=1
i=2,j=0,k=0,l=2
跳到指定的for循环位置可以使用标号。
循环
/**
* 第一个java程序
* @param args
*/
public static void main(String[] args) {
Random random = new Random();
long max = 3000000000L;
int i = 0;
while (i < max) {
i += 123456789;
}
System.out.println(i);
}
结果:空白。
有时候我们在数据库获取的数据是映射成long类型,但是会对数据累加进行一个计算,最终导致超过了Integer.MAX_VALUE(2147483647),然后会从Integer.MIN_VALUE(-2147483648)重新累加。
开发优化
采用Clone()方式创建对象
clone()方法不会调用所含的构造函数,所以速度会更快。
位运算替换算数运算
一维数组代替二维数组
二维数组的访问速度要优于一维数组,但是二维数组比一维数组占用大约10倍左右的空间。
用数字的改进
System.out.println(123_456_789);
System.out.println(123456789);
用来替换123,456,789的千分位替换
分割字符串
对于需要用indexof()和substring()这两个方法,并且用的频繁使用stringtokenizer代替。
性能优化
单线程快还是多线程快?
通常来说,认为多线程快,是因为网络IO消耗影响了线程的执行效率,如果在计算密集型的情况下,单线程比多线程要快,除非将CPU的所有线程都最大化的使用(就是在线程数量不超出CPU线程数的情况下),避免了时间片轮询抢夺CPU资源。
用空间换时间还是时间换空间?
一般来说,在网络传输的过程中,常常使用一些压缩算法,这是时间换空间的方式,但是网络的传输常常因为带宽的原因,因为传输的大小影响时间,所以在这时候使用了压缩算法浪费了一部分时间,整体看来往往节约了更多的时间。
在计算的时候,往往需要空间换时间,例如菜单树的遍历,使用map比list可能浪费了更大的空间,计算速度往往提升了不少,因为减少了重复遍历的时间。