这篇文章将介绍java中提高效率的一些方法。
1.循环条件中的复杂表达式应该独立出来
在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。
例子:
import java.util.vector;
class cel {
void method (vector vector) {
for (int i = 0; i < vector.size (); i++) // violation
; // ...
}
}
更正:
class cel_fixed {
void method (vector vector) {
int size = vector.size ()
for (int i = 0; i < size; i++)
; // ...
}
}
2.使用'system.arraycopy ()'代替通过来循环复制数组
'system.arraycopy ()' 要比通过循环来复制数组快的多。
例子:
public class irb
{
void method () {
int[] array1 = new int [100];
for (int i = 0; i < array1.length; i++) {
array1 [i] = i;
}
int[] array2 = new int [100];
for (int i = 0; i < array2.length; i++) {
array2 [i] = array1 [i]; // violation
}
}
}
更正:
public class irb
{
void method () {
int[] array1 = new int [100];
for (int i = 0; i < array1.length; i++) {
array1 [i] = i;
}
int[] array2 = new int [100];
system.arraycopy(array1, 0, array2, 0, 100);
}
}
3.使用移位操作来代替'a / b'操作,使用移位操作代替'a * b'
例子:
public class sdiv {
public static final int num = 16;
public void calculate(int a) {
int div = a / 4; // should be replaced with "a >> 2".
int div2 = a / 8; // should be replaced with "a >> 3".
int temp = a / 3;
}
}
更正:
public class sdiv {
public static final int num = 16;
public void calculate(int a) {
int div = a >> 2;
int div2 = a >> 3;
int temp = a / 3; // 不能转换成位移操作
}
}
类似的,a*4,a*8可以用int mul = a << 2; int mul2 = a << 3;代替,还有取余运算a=a%8可以用a=a&7代替。但是要权衡可读性问题。除法是整数运算中效率最低的,应该尽量避免。这里补充下&运算的原理,如:
int a=129;
int b=128;
System.out.println("a 和b 与的结果是:"+(a&b));
“a”的值是129,转换成二进制就是10000001,而“b”的值是128,转换成二进制就是10000000。根据与运算符的运算规律,只有两个位都是1,结果才是1,可以知道结果就是10000000,即128。
4.对于boolean值,避免不必要的等式判断
将一个boolean值与一个true比较是一个恒等操作(直接返回该boolean变量的值). 移走对于boolean的不必要操作至少会带来2个好处:
1)代码执行的更快 (生成的字节码少了5个字节);
2)代码也会更加干净 。
例子:
public class ueq
{
boolean method (string string) {
return string.endswith ("a") == true; // violation
}
}
更正:
class ueq_fixed
{
boolean method (string string) {
return string.endswith ("a");
}
}
5. 合理使用string,stringBuffer和stringBuilder
(1).如果要操作少量的数据用 = String
(2).单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
(3).多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
通过StringBuffer的构造函数来设定他的初始化容量,可以明显提升性能。
6.不要在循环体中实例化变量
在循环体中实例化临时变量将会增加内存消耗
例子:
import java.util.vector;
public class loop {
void method (vector v) {
for (int i=0;i < v.size();i++) {
object o = new object();
o = v.elementat(i);
}
}
}
更正:
在循环体外定义变量,并反复使用
import java.util.vector;
public class loop {
void method (vector v) {
object o;
for (int i=0;i<v.size();i++) {
o = v.elementat(i);
}
}
}
7. 在java+Oracle的应用系统开发中,java中内嵌的SQL语言应尽量使用大写形式,以减少Oracle解析器的解析负担。
8.array 数组效率最高,但容量固定,无法动态改变,ArrayList容量可以动态增长,但牺牲了效率。
9.不要使用 i % 2 == 1 来判断是否是奇数,因为i为负奇数时不成立,请使用 i % 2 != 0 来判断是否是奇数,或使用 高效式 (i & 1) != 0来判断。(让我想起了今年腾讯的笔试题)
10.货币单位计算时应该用最小单位,因为小数在java中是无法精确表示的,如:System.out.println(2.00 -1.10);//0.8999999999999999
11.int类型的溢出
我们计算一天中的微秒数:
long microsPerDay = 24 * 60 * 60 * 1000 * 1000;// 正确结果应为:86400000000
System.out.println(microsPerDay);// 实际上为:500654080
问题在于计算过程中溢出了。这个计算式完全是以int运算来执行的,并且只有在运算完成之后,其结果才被提升为long,而此时已经太迟:计算已经溢出。
解决方法使计算表达式的第一个因子明确为long型,这样可以强制表达式中所有的后续计算都用long运算来完成,这样结果就不会溢出:
long microsPerDay = 24L * 60 * 60 * 1000 * 1000;
12.尽量使用final修饰符
带有final修饰符的类是不可派生的。在JAVA核心API中,有许多应用final的例子,例如 java.lang.String。为String类指定final防止了使用者覆盖length()方法。另外,如果一个类是final的,则该类所有方法都是final的。java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能平均提高 50%。
13.用x++,x+=1代替x=x+1能提高效率
14.条件判断时将可能性大的放在前面
15.出于安全考虑,判断语句应该将变量作为比较的对象
如if(a==3)代替为if(3==a)
16.冒泡排序的时候设置一个boolean类型的交换标记可以提高速度(排序好不用再遍历)
例子:
package com.wws.yy;
import java.util.Random;
public class BubbleSortClient {
public static void main(String[] args) {
//构造数据
int[] arr = constructDataArray(15);
System.out.println("---------排序前-----------");
printArrayData(arr);
//冒泡排序
bubbleSort2(arr);
System.out.println("---------排序后-----------");
printArrayData(arr);
}
//构造数据
public static int[] constructDataArray(int length){
int[] arr = new int[length];
Random random = new Random();
for(int i=0;i<length;i++){
arr[i] = random.nextInt(length);
}
return arr;
}
/**
* 冒泡排序方法----第一种方法
* @param arr
*/
public static int[] bubbleSort(int[] arr){
for(int i=0; i<arr.length;i++){
for(int j=i+1;j<arr.length;j++){
if(arr[i] > arr[j]){
//交换数据
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
/**
* 冒泡排序方法----第二种方法
* @param arr
*/
public static int[] bubbleSort2(int[] arr){
for(int i=0;i<arr.length;i++){
for(int j=0;j<arr.length-1-i;j++){
if(arr[j] > arr[j+1]){
//数据交换
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
return arr;
}
//打印数据
public static void printArrayData(int[] arr){
for(int d :arr){
System.out.print(d + " ");
}
System.out.println();
}
}
优化后:
import java.util.Random;
public class BubbleSortClient {
public static void main(String[] args) {
//构造数据
int[] arr = constructDataArray(15);
System.out.println("---------排序前-----------");
printArrayData(arr);
//冒泡排序
bubbleSort4(arr);
System.out.println("---------排序后-----------");
printArrayData(arr);
}
//构造数据
public static int[] constructDataArray(int length){
int[] arr = new int[length];
Random random = new Random();
for(int i=0;i<length;i++){
arr[i] = random.nextInt(length);
}
return arr;
}
/**
* 引入标志位,默认为true
* 如果前后数据进行了交换,则为true,否则为false。如果没有数据交换,则排序完成。
* @param arr
*/
public static int[] bubbleSort4(int[] arr){
boolean flag = true;
int n = arr.length;
while(flag){
flag = false;
for(int j=0;j<n-1;j++){
if(arr[j] >arr[j+1]){
//数据交换
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
//设置标志位
flag = true;
}
}
n--;
}
return arr;
}
//打印数据
public static void printArrayData(int[] arr){
for(int d :arr){
System.out.print(d + " ");
}
System.out.println();
}
}