赞
踩
【小明喜欢上一个刚来的女同事,她是医院里的检验师,为了套近乎就经常跑到她科室去倒开水喝,熟了后就发现她随身的小包包里总放着一把小水果刀,于是我问她:你总放把小刀包里干嘛?她答道:下夜班防身啊!虽然刀小,但是我清楚的知道人的大动脉在哪里!我去!这特么以后还敢撩吗?】
大家好,我录制的视频《Java之优雅编程之道》已经在CSDN学院发布了,有兴趣的同学可以购买观看,相信大家一定会收获到很多知识的。谢谢大家的支持……
视频地址:http://edu.csdn.net/lecturer/994
如何优雅的使用数组???
程序清单 2-1
@Test
public void test(){
//第一种初始化数组格式
String[] a = new String[5];
//第二种初始化数组格式
String b[] = new String[5];
}
通常情况下,大部分的程序员都会选择用第一种初始化数组的格式。但我确实碰到过有少数的开发人员用第二种初始化数组格式。这里我建议使用第一种,主要原因是:大多数人都使用第一种,自然,我们也要少数服从多数。而且从字面意思来看,String[] a 表示:初始化一个字符串(String)数组([]) a,读起来更加顺口。
数组和集合,我们都可以简单的理解为篮子。不同的篮子可以装不同的东西。
对于基本类型,建议你使用数组篮子,相对于集合篮子,它效率更高。具体实例如下:
程序清单 2-1 @Test public void test(){ int sum = 0; //数组装int基本类型 int[] baseTypeArray = new int[10000]; for(int i=0,len = baseTypeArray.length;i < len;i++){ //不存在自动装箱和拆箱的操作 sum = sum + baseTypeArray[i]; } //集合装包装类型 List<Integer> objectTypeList = new ArrayList<>(10000); for(int i=0,len = objectTypeList.size();i < len;i++){ //在这里有自动装箱和拆箱的操作,效率低 sum = sum + objectTypeList.get(i); } }
数组copy有很多种方法,效率不一。我们先看下面具体实例:
程序清单 2-1 /** * 测试4种数组复制效率比较 * @author 阿毅 * @date 2017/2/7. */ public class AyTest { private static final byte[] buffer = new byte[1024*10]; static { for (int i = 0; i < buffer.length; i++) { buffer[i] = (byte) (i & 0xFF); } } private static long startTime; public static void main(String[] args) { startTime = System.nanoTime(); byte[] newBuffer = new byte[buffer.length]; for(int i=0;i<buffer.length;i++) { newBuffer[i] = buffer[i]; } calcTime("forCopy"); startTime = System.nanoTime(); byte[] newBuffer2 = buffer.clone(); calcTime("cloneCopy"); startTime = System.nanoTime(); byte[] newBuffer3 = Arrays.copyOf(buffer, buffer.length); calcTime("arraysCopyOf"); startTime = System.nanoTime(); byte[] newBuffer4 = new byte[buffer.length]; System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); calcTime("systemArraycopy"); } private static void calcTime(String type) { long endTime = System.nanoTime(); System.out.println(type + " cost " +(endTime-startTime)+ " nanosecond"); } }
运行结果:
forCopy cost 711576 nanosecond
cloneCopy cost 53490 nanosecond
arraysCopyOf cost 119946 nanosecond
systemArraycopy cost 39712 nanosecond
多运行几次,我们得出数组复制效率:
System.arraycopy > clone > Arrays.copyOf > for
综上所述,当复制大量数据时,使用System.arraycopy()命令。
因为java中没有二维数组的概念,只有数组的数组。所以对数组的数组进行拷贝,无论对clone或者arraycopy,都只是拷贝其中的引用。事实上,还是指向同一个值。具体实例如下:
程序清单 2-1 @Test public void test(){ //一维数组的拷贝 int[] a = {5,2,0,1,3,1,4}; int[] b = a.clone(); b[0]=10; System.out.println(a[0] + " copy " + b[0]); //打印结果:5 copy 10 //二维数组的拷贝:{5,2,0} 和 {1,3,1,4}这两个一维数组都有引用指向它们 int[][] c = {{5,2,0},{1,3,1,4}}; int[][] d = c.clone(); d[0][0]=10; System.out.println(c[0][0] + " coyp " + d[0][0]); //打印结果:10 coyp 10 //二维数组的拷贝:{5,2,0} 和 {1,3,1,4}这两个一维数组都有引用指向它们 int[][] e = {{5,2,0},{1,3,1,4}}; int[][] f = {{},{}}; System.arraycopy(e, 0, f, 0, e.length); f[0][0]=10; System.out.println(e[0][0] + " coyp " + f[0][0]); //打印结果:10 coyp 10 }
从上面的例子可以看出,利用clone和System.arraycopy进行二维数组的拷贝,都是浅拷贝。在真实项目中,我们要警惕使用。
在上面的警惕二维数组的拷贝中我们已经知道,clone和System.arraycopy都是浅拷贝,下面提供一些深拷贝的优雅方法:
例:
程序清单 2-1 @Test public void test(){ Boy[] boys = new Boy[1]; Boy boy = new Boy("60","ay",new Girl("30","al")); boys[0] = boy; //利用org.apache.commons.lang3.SerializationUtils进行深度clone Boy[] coypBoys = (Boy[])SerializationUtils.clone(boys); //clone是浅clone //Boy[] coypBoys = boys.clone(); coypBoys[0].id = "change_60"; coypBoys[0].name = "change_ay"; coypBoys[0].girl.id = "change_girl_30"; coypBoys[0].girl.name = "change_girl_al"; for(int i=0,len = boys.length;i<len;i++){ System.out.println("the origin of id :" + boys[i].id); System.out.println("the origin of name :" + boys[i].name); System.out.println("the origin of girl id :" + boys[i].girl.id); System.out.println("the origin of girl name :" + boys[i].girl.name); } for(int i=0,len = coypBoys.length;i<len;i++){ System.out.println("the copy of id :" + coypBoys[i].id); System.out.println("the copy of name :" + coypBoys[i].name); System.out.println("the copy of girl id :" + coypBoys[i].girl.id); System.out.println("the copy of girl name :" + coypBoys[i].girl.name); } }
执行结果:
the origin of id :60
the origin of name :ay
the origin of girl id :30
the origin of girl name :al
the copy of id :change_60
the copy of name :change_ay
the copy of girl id :change_girl_30
the copy of girl name :change_girl_al
上面例子中,我们利用 apache 提供的工具类 SerializationUtils 进行深度clone,避免重复造轮子。有一点需要注意的是,Boy 和 Girl 类都要实现 Serializable 接口。具体如下:
程序清单 2-1 class Boy implements Serializable{ public String id; public String name; public Girl girl; Boy(String id,String name,Girl girl){ this.id = id; this.name = name; this.girl = girl; } } class Girl implements Serializable{ public String id; public String name; Girl(String id,String name){ this.id = id; this.name = name; } }
我们把 //Boy[] coypBoys = boys.clone();注释打开,运行程序,结果如下:
the origin of id :change_60
the origin of name :change_ay
the origin of girl id :change_girl_30
the origin of girl name :change_girl_al
the copy of id :change_60
the copy of name :change_ay
the copy of girl id :change_girl_30
the copy of girl name :change_girl_al
可以证实,普通的clone只是浅拷贝而已。
在项目开发中,如果有碰到二维数组,我们要机智的把它转化为一维数组。因为一维数组比较容易理解,而且性能会比二维数组高。
@Test public void test(){ int arr[][] = new int[1000][1000]; long startTime = System.currentTimeMillis(); System.out.println("start time is :" + startTime); for(int i=0;i<1000;i++){ //在for循环中进行方法调用,影响性能 for(int j=0;j<arr[0].length;j++){ arr[i][j] = j; } } long endTime = System.currentTimeMillis(); System.out.println("consume time is : " + (endTime - startTime)); // -------------------------------------------------------------- startTime = System.currentTimeMillis(); System.out.println("start time is :" + startTime); //这里是重点 int len = arr[0].length; for(int i=0;i<1000;i++){ for(int j=0;j<len;j++){ arr[i][j] = j; } } endTime = System.currentTimeMillis(); System.out.println("consume time is : " + (endTime - startTime)); }
运行结果:
start time is :1487563038580
consume time is : 19
start time is :1487563038600
consume time is : 9
如果二维数组没办法转化为一维数组,那么我们要极力避免在循环体内进行方法调用,如上面例子中的arr[0].length,每循环一次都会执行一次length方法,执行时长也多出10ms。因此,我们要把arr[0].length抽出来,减少方法执行次数。
我们建议用集合,栈和队列等按顺序存取元素的数据结构来取代数组。在之前,我们提过:对于存放基本类型,优先选择用数组。而对于存放其他类型的数据,我们建议用集合,栈和队列。具体原因如下:在数组里随机访问就像在程序里随机使用goto语句一样,这样的访问很容易变得难以管理且容易出错。要证明其是否正确也困难。
来自山下英子《断舍离》
【甲向乙诉苦:“上星期,一粒沙子钻进了我妻子的眼睛,花50元请医生才把它清理出来。”乙不屑地说:“那算得了什么,上星期,一件皮大衣入了我妻子的眼,我花费了3000元。”
永远不要以为自己的境遇是最值得说的,你的听众会认为他的境遇更值得说,因为人是以自我为中心的动物。】
【1】Thinking in Java (书籍)
【2】Agile Java(书籍)
【3】编写高质量代码:改善Java程序的151个建议(书籍)
【4】Java程序性能优化 让你的Java程序更快、更稳定(书籍)
【5】Effective Java中文版 第2版.Joshua Bloch(书籍)
如果有带给你一丝丝小快乐,就让快乐继续传递下去,欢迎点赞、顶、欢迎留下宝贵的意见、多谢支持!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。