程序的性能受到代码质量的直接影响。今天给大家主要介绍一些代码编写的小技巧和惯例。虽然看起来有些是微不足道的编程技巧,却可能为系统性能带来成倍的提升,因此还是值得关注的。

1、慎用异常

在Java开发中,经常使用try-catch进行错误捕获,但是try-catch语句对系统性能而言是非常糟糕的。虽然一次try-catch中,无法察觉到她对性能带来的损失,但是一旦try-catch语句被应用于循环或是遍历体内,就会给系统性能带来极大的伤害。

以下是一段将try-catch应用于循环体内的示例代码:

@Testpublic void test11() {long start = System.currentTimeMillis();int a = 0;for(int i=0;i<1000000000;i++){try {a++;}catch (Exception e){e.printStackTrace();}}long useTime = System.currentTimeMillis()-start;System.out.println("useTime:"+useTime);}

上面这段代码运行结果是:

useTime:10

下面是一段将try-catch移到循环体外的代码,那么性能就提升了将近一半。如下:

@Testpublic void test(){long start = System.currentTimeMillis();int a = 0;try {for (int i=0;i<1000000000;i++){a++;}}catch (Exception e){e.printStackTrace();}long useTime = System.currentTimeMillis()-start;System.out.println(useTime);}

运行结果:

useTime:6

2、使用局部变量

调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。

下面是一段使用局部变量进行计算的代码:

@Testpublic void test11() {long start = System.currentTimeMillis();int a = 0;for(int i=0;i<1000000000;i++){a++;}long useTime = System.currentTimeMillis()-start;System.out.println("useTime:"+useTime);}

运行结果:

useTime:5

将局部变量替换为类的静态变量:

static int aa = 0;@Testpublic void test(){long start = System.currentTimeMillis();for (int i=0;i<1000000000;i++){aa++;}long useTime = System.currentTimeMillis()-start;System.out.println("useTime:"+useTime);}

运行结果:

useTime:94

通过上面两次的运行结果,可以看出来局部变量的访问速度远远高于类成员变量。

3、位运算代替乘除法

在所有的运算中,位运算是最为高效的。因此,可以尝试使用位运算代替部分算术运算,来提高系统的运行速度。最典型的就是对于整数的乘除运算优化。

下面是一段使用算术运算的代码:

@Testpublic void test11() {long start = System.currentTimeMillis();int a = 0;for(int i=0;i<1000000000;i++){a*=2;a/=2;}long useTime = System.currentTimeMillis()-start;System.out.println("useTime:"+useTime);}

运行结果:

useTime:1451

将循环体中的乘除运算改为等价的位运算,代码如下:

@Testpublic void test(){long start = System.currentTimeMillis();int aa = 0;for (int i=0;i<1000000000;i++){aa<<=1;aa>>=1;}long useTime = System.currentTimeMillis()-start;System.out.println("useTime:"+useTime);}

运行结果:

useTime:10

上两段代码执行了完全相同的功能,在每次循环中,都将整数乘以2,并除以2。但是运行结果耗时相差非常大,所以位运算的效率还是显而易见的。

4、提取表达式

在软件开发过程中,程序员很容易有意无意地让代码做一些“重复劳动”,在大部分情况下,由于计算机的高速运行,这些“重复劳动”并不会对性能构成太大的威胁,但若希望将系统性能发挥到极致,提取这些“重复劳动”相当有意义。

比如以下代码中进行了两次算术计算:

@Testpublic void testExpression(){long start = System.currentTimeMillis();double d = Math.random();double a = Math.random();double b = Math.random();double e = Math.random();double x,y;for(int i=0;i<10000000;i++){x = d*a*b/3*4*a;y = e*a*b/3*4*a;}long useTime = System.currentTimeMillis()-start;System.out.println("useTime:"+useTime);}

运行结果:

useTime:21

仔细看能发现,两个计算表达式的后半部分完全相同,这也意味着在每次循环中,相同部分的表达式被重新计算了。

那么改进一下后就变成了下面的样子:

@Testpublic void testExpression99(){long start = System.currentTimeMillis();double d = Math.random();double a = Math.random();double b = Math.random();double e = Math.random();double p,x,y;for(int i=0;i<10000000;i++){p = a*b/3*4*a;x = d*p;y = e*p;}long useTime = System.currentTimeMillis()-start;System.out.println("useTime:"+useTime);}

运行结果:

useTime:11

通过运行结果我们可以看出来具体的优化效果。

同理,如果在某循环中需要执行一个耗时操作,而在循环体内,其执行结果总是唯一的,也应该提取到循环体外。

例如下面的代码:

for(int i=0;i<100000;i++){x[i] = Math.PI*Math.sin(y)*i;
}

应该改进成下面的代码:

//提取复杂,固定结果的业务逻辑处理到循环体外
double p = Math.PI*Math.sin(y);
for(int i=0;i<100000;i++){x[i] = p*i;
}

5、使用arrayCopy()

数组复制是一项使用频率很高的功能,JDK中提供了一个高效的API来实现它。

/*** @param      src      the source array.* @param      srcPos   starting position in the source array.* @param      dest     the destination array.* @param      destPos  starting position in the destination data.* @param      length   the number of array elements to be copied.* @exception  IndexOutOfBoundsException  if copying would cause*               access of data outside array bounds.* @exception  ArrayStoreException  if an element in the <code>src</code>*               array could not be stored into the <code>dest</code> array*               because of a type mismatch.* @exception  NullPointerException if either <code>src</code> or*               <code>dest</code> is <code>null</code>.*/public static native void arraycopy(Object src,  int  srcPos,Object dest, int destPos,int length);

如果在应用程序中需要进行数组复制,应该使用这个函数,而不是自己实现。

下面来举例:

@Testpublic void testArrayCopy(){int size = 100000;int[] array = new int[size];int[] arraydest = new int[size];for(int i=0;i<array.length;i++){array[i] = i;}long start = System.currentTimeMillis();for (int k=0;k<1000;k++){//进行复制System.arraycopy(array,0,arraydest,0,size);}long useTime = System.currentTimeMillis()-start;System.out.println("useTime:"+useTime);}

运行结果:

useTime:59

相对应地,如果在程序中,自己实现数组复制,其等价代码如下:

@Testpublic void testArrayCopy99(){int size = 100000;int[] array = new int[size];int[] arraydest = new int[size];for(int i=0;i<array.length;i++){array[i] = i;}long start = System.currentTimeMillis();for (int k=0;k<1000;k++){for(int i=0;i<size;i++){arraydest[i] = array[i];}}long useTime = System.currentTimeMillis()-start;System.out.println("useTime:"+useTime);}

运行结果:

useTime:102

通过运行结果可以看出效果。

因为System.arraycopy()函数是native函数,通常native函数的性能要优于普通函数。仅出于性能考虑,在程序开发时,应尽可能调用native函数。

6、使用Buffer进行I/O操作

除NIO外,使用Java进行I/O操作有两种基本方式;

  • 使用基于InpuStream和OutputStream的方式;

  • 使用Writer和Reader;

无论使用哪种方式进行文件I/O,如果能合理地使用缓冲,就能有效地提高I/O的性能。

InputStream、OutputStream、Writer和Reader配套使用的缓冲组件。

如下图:

使用缓冲组件对文件I/O进行包装,可以有效提升文件I/O的性能。

下面是一个直接使用InputStream和OutputStream进行文件读写的代码:

@Testpublic void testOutAndInputStream(){try {DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("/IdeaProjects/client2/src/test/java/com/client2/cnblogtest/teststream.txt"));long start = System.currentTimeMillis();for(int i=0;i<10000;i++){dataOutputStream.writeBytes(Objects.toString(i)+"\r\n");}dataOutputStream.close();long useTime = System.currentTimeMillis()-start;System.out.println("写入数据--useTime:"+useTime);//开始读取数据long startInput = System.currentTimeMillis();DataInputStream dataInputStream = new DataInputStream(new FileInputStream("/IdeaProjects/client2/src/test/java/com/client2/cnblogtest/teststream.txt"));while (dataInputStream.readLine() != null){}dataInputStream.close();long useTimeInput = System.currentTimeMillis()-startInput;System.out.println("读取数据--useTimeInput:"+useTimeInput);}catch (Exception e){e.printStackTrace();}}

运行结果:

写入数据--useTime:660
读取数据--useTimeInput:274

使用缓冲的代码如下:

@Testpublic void testBufferedStream(){try {DataOutputStream dataOutputStream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("/IdeaProjects/client2/src/test/java/com/client2/cnblogtest/teststream.txt")));long start = System.currentTimeMillis();for(int i=0;i<10000;i++){dataOutputStream.writeBytes(Objects.toString(i)+"\r\n");}dataOutputStream.close();long useTime = System.currentTimeMillis()-start;System.out.println("写入数据--useTime:"+useTime);//开始读取数据long startInput = System.currentTimeMillis();DataInputStream dataInputStream = new DataInputStream(new BufferedInputStream(new FileInputStream("/IdeaProjects/client2/src/test/java/com/client2/cnblogtest/teststream.txt")));while (dataInputStream.readLine() != null){}dataInputStream.close();long useTimeInput = System.currentTimeMillis()-startInput;System.out.println("读取数据--useTimeInput:"+useTimeInput);}catch (Exception e){e.printStackTrace();}}

运行结果:

写入数据--useTime:22
读取数据--useTimeInput:12

通过运行结果,我们能很明显的看出来使用缓冲的代码,无论在读取还是写入文件上,性能都有了数量级的提升。

使用Wirter和Reader也有类似的效果。

如下代码:

@Testpublic void testWriterAndReader(){try {long start = System.currentTimeMillis();FileWriter fileWriter = new FileWriter("/IdeaProjects/client2/src/test/java/com/client2/cnblogtest/teststream.txt");for (int i=0;i<100000;i++){fileWriter.write(Objects.toString(i)+"\r\n");}fileWriter.close();long useTime = System.currentTimeMillis()-start;System.out.println("写入数据--useTime:"+useTime);//开始读取数据long startReader = System.currentTimeMillis();FileReader fileReader = new FileReader("/IdeaProjects/client2/src/test/java/com/client2/cnblogtest/teststream.txt");while (fileReader.read() != -1){}fileReader.close();long useTimeInput = System.currentTimeMillis()-startReader;System.out.println("读取数据--useTimeInput:"+useTimeInput);}catch (Exception e){e.printStackTrace();}}

运行结果:

写入数据--useTime:221
读取数据--useTimeInput:147

对应的使用缓冲的代码:

@Testpublic void testBufferedWriterAndReader(){try {long start = System.currentTimeMillis();BufferedWriter fileWriter = new BufferedWriter(new FileWriter("/IdeaProjects/client2/src/test/java/com/client2/cnblogtest/teststream.txt"));for (int i=0;i<100000;i++){fileWriter.write(Objects.toString(i)+"\r\n");}fileWriter.close();long useTime = System.currentTimeMillis()-start;System.out.println("写入数据--useTime:"+useTime);//开始读取数据long startReader = System.currentTimeMillis();BufferedReader fileReader = new BufferedReader(new FileReader("/IdeaProjects/client2/src/test/java/com/client2/cnblogtest/teststream.txt"));while (fileReader.read() != -1){}fileReader.close();long useTimeInput = System.currentTimeMillis()-startReader;System.out.println("读取数据--useTimeInput:"+useTimeInput);}catch (Exception e){e.printStackTrace();}}

运行结果:

写入数据--useTime:157
读取数据--useTimeInput:59

通过运行结果可以看出,使用了缓冲后,无论是FileReader还是FileWriter的性能都有较为明显的提升。

在上面的例子中,由于FileReader和FilerWriter的性能要优于直接使用FileInputStream和FileOutputStream所以循环次数增加了10倍。

IT技术分享社区

个人博客网站:https://programmerblog.xyz

文章推荐程序员效率:画流程图常用的工具程序员效率:整理常用的在线笔记软件远程办公:常用的远程协助软件,你都知道吗?51单片机程序下载、ISP及串口基础知识硬件:断路器、接触器、继电器基础知识

后端技术:Java代码优秀案例,一定对你有提升!相关推荐

  1. 看完这些 Java 代码优秀案例,一定对你有提升!

    点击上方 "程序员小乐"关注, 星标或置顶一起成长 每天凌晨00点00分, 第一时间与你相约 每日英文 This is the way I am. I treat well tho ...

  2. 看完这些 Java 代码优秀案例,一定对你有提升

    前言 程序的性能受到代码质量的直接影响.这次主要介绍一些代码编写的小技巧和惯例.虽然看起来有些是微不足道的编程技巧,却可能为系统性能带来成倍的提升,因此还是值得关注的. 慎用异常 在Java开发中,经 ...

  3. 23种设计模式(java代码实现案例)

    设计模式 创造型.结构型.行为型 创建型: 1.(类)工厂方法(Factory Method) 意图 ​ 定义一个用于创建对象的接口,让子类决定实例化哪一个类.使一个类的实例化延迟到了子类 适用性 ​ ...

  4. 【求解器】超级强大的数学规划模型求解器Cplex,导入idea+java代码简单案例详解

    文章目录 前言 一.下载cplex 二.使用步骤 1.打开idea,创建一个新项目 2.导入cplex的包 3.测试,用cplex求解一个简单的线性规划问题 总结 前言 CPLEX是一种数学优化技术. ...

  5. Java代码混淆案例(附反编译工具)

       我们开发的软件上线后,经常会遇到核心代码不希望给别人抄袭,但系统是用Java开发的,又无法避免被反编译的情况,这样可以用代码混淆的方式来解决. 一.编译 顾名思义,就是将我们写的代码运行一遍,然 ...

  6. 怎么又双叒叕得奖了!得帆入选中国2022低代码优秀厂商代表

    近日,国内权威机构海比研究院发布<2022·中国低代码/无代码市场研究及选型评估报告>,报告调研大量厂商及企业用户,通过对厂商品牌.产品.技术.服务.安全.价值6大能力进行分析评估,帮助企 ...

  7. Java OCR tesseract 图像智能字符识别技术 Java实现

    Java OCR tesseract 图像智能字符识别技术 Java代码实现 接着上一篇OCR所说的,上一篇给大家介绍了tesseract 在命令行的简单用法,当然了要继承到我们的程序中,还是需要代码 ...

  8. Java后端技术精选优秀博文

    一.Java基础 1.Java中枚举类型Enum的一种使用方式 2.Java性能优化之字符串优化处理 3.Java 面试题问与答:编译时与运行时 4.Java中OIO与NIO的简单区别 5.为什么Ja ...

  9. Java后端技术栈,到底如何深入学习?

    Java,是现阶段中国互联网公司中,覆盖度最广的研发语言.有不少朋友问,如何深入学习Java后端技术栈,今天分享一个,互联网牛人整理出来的Java深入学习路线图,以及免费学习资料. 一.阅读源码 深入 ...

最新文章

  1. 捋一下测序后生信分析内容及其常用软件
  2. linux 心跳灯_Linux下点亮第一个LED灯
  3. 导入数据库时报错1067 – Invalid default value for ‘字段名’
  4. 树莓派摄像头基础配置及测试
  5. Drools集成SpringBootStarter
  6. Windows Server 2008 配置使用动态IP和备用地址
  7. MindSpore实践:对篮球运动员目标的检测
  8. radio选中事件怎么绑定_Vue双向绑定
  9. java 测试 jar_java – 从可执行jar运行spring测试
  10. python调用shell命令 批量执行python程序
  11. 我要看的学习网站——php
  12. 算法笔记(个人用)(不定期更新)
  13. 零基础语法入门三十一讲[被动语态 (1)]被动语态的构成和含义
  14. Visual Prompt Tuning (VPT)
  15. EXCEL填入数据,自动出现当天日期
  16. docker GitLab-runner CI/CD持续集成
  17. 零基础计算机英语教程,零基础学英语语法的方法
  18. 王道书P41 T21(单链表实现)
  19. WPS 无法覆盖选中文字
  20. NSF 与NSR 与GR

热门文章

  1. USB主机是如何检测到设备的插入的呢?
  2. centos 6 安装mosh 1.2
  3. ubuntu下命令安装与卸载软件方法
  4. InfiniBand简介
  5. C语言变长数组 struct中char data[0]的用法
  6. 伺服驱动器的 三环控制 电流环 速度环 位置环
  7. 期刊论文格式模板 电子版_期刊论文的框架结构
  8. 电脑显示器变色_电脑维修(看完后就可以开一家自己的电脑维修店!)
  9. 编译py-faster-rcnn全过程
  10. 网博士自助建站系统_自助建站:自助建站到底好还是不好?