当前位置:网站首页 > 国际新闻 > 正文

丁丁,Java程序功能优化:十年码农总结的编程小技巧,文玩

admin 0

程序的功用受代码质量的直接影响。

在本文中,首要介绍一些代码编写的小技巧和常规,这些技巧有助于在代码级别上进步体系功用。

1、慎用反常

在Java软件开发中,常常运用 try-catch 进行过错捕获,可是,try-catch 句子对体系功用而言是十分糟糕的。尽管在一次 try-catch中,无法察觉到它对功用带来的丢失,可是,一旦try-catch被应用于循环之中,就会给体系功用带来极大的损伤。

以下是一段将try-catch应用于for循环内的示例

这段代码我运转时刻是 27211 ms。假如将try-catch移到循环体外,那么就能进步体系功用,如下代码

运转耗时 15647 ms。可见tyr-catch对体系功用的影响。

2丁丁,Java程序功用优化:十年码农总结的编程小技巧,文玩、运用部分环境

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

下面是一段测试用例

// private static int a = 0;

public static voi黑丝足控d main(String[] args) { int a = 0; long start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) {

a = a + 1;

System.out.println(i);

}

System.out.println(System.currentTimeMillis() - start);

}

运转成果很明显,运用静态变量耗时15677ms,运用部分变量耗时13509ms。由此可见,北京太平间守夜员急招部分变量的拜访速度高于类的成员变量。

3、位运算代替乘除法

在一切的运算中,位运算是最为高效丁丁,Java程序功用优化:十年码农总结的编程小技巧,文玩的。因而,能够测验运用位运算代替部分算术运算,来进步体系的运转速度。

比方在HashMap的源码中运用了位运算

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

static final int MAXIMUM_CAPACITY = 1 << 30;

关于整数的乘除运算优化

a*=2

a/=2

用位运算能够写为

a<<=1a>>=1

4、替换switch

关键字 switch 句子用于多条件判别, switch 句子的功用相似于 if-else 句子,两者功用也差不多。因而,不能说 switch 句子会下降体系的功用。可是,在绝大部分情况下,switch 句子仍是有功用进步空间的。

来看下面的比方:

public static void main(String[] args) { l反常重口味ong start = System.currentTimeMillis(); int re = 0; for (int i = 0;i<1000000;i++){

re = switchInt(i);

System.out.println(re);

}

System.out.println(System.currentTimeMillis() - start+"毫秒");//17860

} p纳米神兵中文版ublic static int switchInt(int z){ int i = z%10+1; switch (i){ case 1:return 3; case 2:return 6; case 3:return 7; case 4:return 8; case 5:return 10; case 6:return 16; case 7:return 18; case 8:return 44; default:r沈晴瑜eturn -1;

}

}

就分支逻辑而言,这种 switch 形式的功用并不差。可是假如换一种新的思路代替switch,完成相同的程序功用,功用就能有很大的进步空间。

public static void main(String[] args) { lon容佩穿耳g start = System.currentTimeMillis(); int re = 0; int[] sw = new int[]{0,3,6,7,8,10,16,18,44}; for (int i = 0;i<1000000;i++){

re = arrayInt(sw,i);

System.out.println(re);

}

System.out.println(System.currentTimeMillis() - start+"毫秒");//12590

}

public static int arrayInt( int[] sw,int z){ int i = z%10+1; if (i>7 || i<1){ return -1;

}else { return sw[i];

}

}

以上代码运用全新的思路,运用一个接连的数组代替了 switch 句子。因为对数据的随机拜访是十分快的,至少好于 switch 的分支判别。经过试验,运用switch的句子耗时17860ms,运用数组的完成只耗时12590ms,进步了5s多。在软件开发中,换一种思路或许会取得更好的作用,比方运用数组代替switch句子便是便是一个很好的比方。在此我向咱们引荐一个架构学习沟通裙。沟通学习裙号:821169538,里边会共享一些资深架构师录制的视频录像

5、一维数组代替二维数组

因为数组的随机拜访的功用十分好,许多JDK类李天煜库,如ArrayList、Vector等都是运用了数组作为其数组完成。可是,作为软件男上司开发人员也有必要知道,一位数组和二维数组的拜访速度是不相同的。一位数组的拜访速度要优于二维数组。因而,在功用灵敏的体系中要运用二维数组的,能够测验经过可靠地算法,将二维数组转为一维数组再进行处理,以进步体系的响应速度。

6、提取表达式

在软件开发过程中,程序员很简单有意无意让代码做一些“重复劳动”,在大部分情况下,因为核算机的通知运转,这些“重复劳动”并不会对功用构成太大的要挟,但若将体系功用发挥到极致,提取这些“重复劳动”适当有意义。

来看下面的测试用例:

@Test public void test(){ long start = System.currentTimeMillis();

ArrayList list = new ArrayList(); for (int i = 0;i<100000;i++){

System.out.println(list.add(i));

} //以上是为了做准备

for (int i = 0;i

System.out.println(list.get(艾卡时髦酒店i));

}

System.out.println(System.currentTimeMillis() - start);//5444

}

假如咱们把list.size()办法提取出来,优化后的代码如下:

@Test public void test(){ 吴宓和周莹long start = System.currentTimeMillis();

ArrayList list = new ArrayList(); for (int i = 0;i<100000;i++){

System.out.println(list.add(i));

} //以上是为了做准备

int n = list.size(); for (int i丁丁,Java程序功用优化:十年码农总结的编程小技巧,文玩 = 0;i

System.out.println(list.get(i));

}

System.out.println(System.currentTimeMillis() - start);//3514

}

在我的机器上,前者耗时5444ms,后者耗时3514ms,相差2s左右,可见,提取重复的操作是适当有意义的。

7、打开循环

与前面所介绍的优化技巧略有不同,笔者以为打开循环是一种在极点情况下运用的优化手法,因为打开循环很或许会影响代码的可读性和可保护性,而这两者对软件体系来万界造化珠说也是极为重要的。可是,当功用问题成为体系首要矛盾时,打开循环肯定是丁丁,Java程序功用优化:十年码农总结的编程小技巧,文玩一种值得测验的技术。

8、布尔运算代替位运算

尽管位运算的速度远远高于算术运算,可是在条件判别时,运用位运算代替布尔运算却是十分过错的挑选。

在条件判别时,Java会对布尔运算做适当充沛的优化。假设有表达式 a,b,c 进行布尔运算“a&&b&&c” ,依据逻辑与的特色,只要在整个布尔表达式中有一项回来false,整个表达式就回来false,因而,当表达式a为false时,该表达式将当即回来1024bt false ,而不会再去核算表达式b 和c。同理,当核算表达式为“a||b||c”时,也是相同。

若运用位运算(按位与”&“、按位或”|“)代替逻辑与和逻辑或,尽管位运算自身没有功用问题,可是位运算总是要将一切的子表达式悉数核算完成后,再给出终究成果。因而,从这个视点来说,运用位运算代替布尔运算会使体系进行许多无效核算。

9、运用arrayCopy()

数组仿制凯夫拉尔是一项运用频率很高的功用,JDK中供给了一个高效的API来完成它:

假如在应用程序需求进行数组仿制,应该运用这个函数带带大师姐,而不是自己完成。

办法代码:

public static native void arraycopy(Object src, int srcPos,

Object dest, int destPos, int length);

它的用法是将源数组 src 从索引 srcPos 处仿制到方针数组 dest 的 索引destPos处,仿制的长度为 length。

System.arraycopy() 办法是 native 办法,一般 native 办法的功用要优于一般的办法。仅出于功用考虑,在软件开发中,尽或许调用 native 办法。

10、运用Buffer进行I/O流操作

除NIO外,运用 Java 进行 I/O操作有两种根本办法:

运用根据InputStream 和 OutputStream 的办法;(字节省)

运用丁丁,Java程序功用优化:十年码农总结的编程小技巧,文玩 Writer 和 Reader。(字符流)

不管运用哪种办法进行文件 I/O,假如能合理地运用缓冲,就能有用的进步I/O的功用。

11、运用clone()代替new

在Java中新建目标实例最常用的办法是运用 new 关键字。JDK对 new 的支撑十分好,运用 new 关键字创立轻量级目标时,速度十分快。可是,关于重量级目标,因为目标在结构函数中或许会进行一些杂乱且耗时的操作,因而,结构函数的执行时刻或许会比较长。导致体系短期内无法取得很多的实例。为了处理这个问题,能够运用Object.clone() 办法。

Object.clone() 办法能够绕过结构函数,快速仿制一个目标实例。可是,在默许情况下,clone()办法生成的实例仅仅原目标的浅复制。

这儿不得不提Java只要值传递了,关于这点,我的了解是根本数据类型引证的是值,一般目标引证的也是值,不过这个一般目标引证的值其实是一个目标的地址。代码示例:在此我向咱们引荐一个架构学习沟通裙。沟通学习裙号:821169538,里边会共享一些资深架构师录制的视频录像

int i = 0; int j = i; //i的值是0

User user1 = new User();

User user2 = user1; //user1值是new User()的内存地址

假如需求深复制,则需求从头完成 clone(丁丁,Java程序功用优化:十年码农总结的编程小技巧,文玩) 付小墨办法。下面看一下ArrayList完成的clone()办法:

public Object clone() { try {

ArrayListv = (ArrayList) 丁丁,Java程序功用优化:十年码农总结的编程小技巧,文玩super.clone();

v.elementData = Arrays.copyOf(elementData, size);

v.modCount = 0上瘾床戏; return v;

} catch (CloneNotSupportedExcep相公请隐身tion e) { // this shouldn't happen, since we are Cloneable

throw new InternalError(e);

}

}

在ArrayList的clone()办法中,首要运用 super.clone() 办法生成一份浅复制目标。然后复制一份新的elementData数组让新的ArrayList去引证。使克隆后的ArrayList目标周明艺与原目标持有不同的引证,完成了深复制。

12、静态办法代替实例办法

运用 static 关键字描绘的办法为静态办法。在Java中,因为实例办法需求保护一张相似虚函数表的结构,以完成对多态的支撑。与静态办法比较,实例办法的调用需求更多的资源。因而,关于一些常用的东西类办法,没有对其进行重载的必要,那么将它们声明为 static,便能够加快办法的调用。一起,调用 s滑走强化tatic 办法不需求生成类的实例。比调用实例办法更为便利、易用。