分享程序网
首页
  • java
微服务
微前端
环境搭建
数据库
设计模式
算法
软件
解决问题
链接
首页
  • java
微服务
微前端
环境搭建
数据库
设计模式
算法
软件
解决问题
链接
  • java

    • JDK
    • JVM
    • JAVA优化

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

三目表达式核心有以下三点:

  1. 如果第二个和第三个操作数是相同的类型,那么就是条件表达式类型。
  2. 如果一个操作数是T(char,byte,short),另一个是int,值类型可以用T表示,那么三目表达式的类型就是T。
  3. 否则就对操作数进行二进制数字提升
	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可能浪费了更大的空间,计算速度往往提升了不少,因为减少了重复遍历的时间。

Last Updated:
Contributors: chengli
Prev
JVM