Fork me on GitHub

Java代码优化小结(二)

(21)将常量声明为static final,并以大写命名

这样在编译期间就可以把这些内容放入常量池中,避免运行期间计算生成常量的值。另外,将常量的名字以大写命名也可以方便区分出常量与变量

(22)不要创建一些不使用的对象,不要导入一些不使用的类

这毫无意义,如果代码中出现”The value of the local variable i is not used”、”The import java.util is never used”,那么请删除这些无用的内容

(23)程序运行过程中避免使用反射

反射是Java提供给用户一个很强大的功能,功能强大往往意味着效率不高。不建议在程序运行过程中使用尤其是频繁使用反射机制,特别是Method的invoke方法,如果确实有必要,一种建议性的做法是将那些需要通过反射加载的类在项目启动的时候通过反射实例化出一个对象并放入内存—-用户只关心和对端交互的时候获取最快的响应速度,并不关心对端的项目启动花多久时间。

(24)使用数据库连接池和线程池

这两个池都是用于重用对象的,前者可以避免频繁地打开和关闭连接,后者可以避免频繁地创建和销毁线程。

(25)使用带缓冲的输入输出流进行IO操作
带缓冲的输入输出流,即BufferedReader、BufferedWriter、BufferedInputStream、BufferedOutputStream,这可以极大地提升IO效率。

(26)顺序插入和随机访问比较多的场景使用ArrayList,元素删除和中间插入比较多的场景使用LinkedList
这个,理解ArrayList和LinkedList的原理就知道了。

(27)不要让public方法中有太多的形参
public方法即对外提供的方法,如果给这些方法太多形参的话主要有两点坏处:

违反了面向对象的编程思想,Java讲求一切都是对象,太多的形参,和面向对象的编程思想并不契合
参数太多势必导致方法调用的出错概率增加

至于这个”太多”指的是多少个,3、4个吧。比如我们用JDBC写一个insertStudentInfo方法,有10个学生信息字段要插如Student表中,可以把这10个参数封装在一个实体类中,作为insert方法的形参。

(28)字符串变量和字符串常量equals的时候将字符串常量写在前面
这是一个比较常见的小技巧了,如果有以下代码:

 1 String str = "123" ;
 2 if (str.equals( "123" )){
 3     ...
 4 }
 5 
 6 //建议修改为:
 7 String str = "123" ;
 8 if ( "123" .equals(str)){
 9     ...
10 }

这么做主要是可以避免空指针异常。

(29)请知道,在java中if (i == 1)和if (1 == i)是没有区别的,但从阅读习惯上讲,建议使用前者

(30)不要对数组使用toString()方法
看一下对数组使用toString()打印出来的是什么:

public static void main(String[] args){
    int [] is = new int []{ 1 , 2 , 3 };
    System.out.println(is.toString());
}
//结果是:[I @18a992f

本意是想打印出数组内容,却有可能因为数组引用is为空而导致空指针异常。不过虽然对数组toString()没有意义,但是对集合toString()是可以打印出集合里面的内容的,因为集合的父类AbstractCollections<E>重写了Object的toString()方法。

(31)不要对超出范围的基本数据类型做向下强制转型
这绝不会得到想要的结果:

1 public static void main(String[] args){
2     long l = 12345678901234L;
3     int i = ( int )l;
4     System.out.println(i);
5 }

我们可能期望得到其中的某几位,但是结果却是:1942892530
转换成二进制:Java中long是8个字节64位的,int型数据是4个字节32位的,从低位取出long转换的这串二进制数据的前32位。
得到两个结论:

  • 1、整型默认的数据类型是int,long l = 12345678901234L,这个数字已经超出了int的范围了,所以最后有一个L,表示这是一个long型数。顺便,浮点型的默认类型是double,所以定义float的时候要写成”"float f = 3.5f”
  • 2、接下来再写一句”int ii = l + i;”会报错,因为long + int是一个long,不能赋值给int。

(32)公用的集合类中不使用的数据一定要及时remove掉
如果一个集合类是公用的(也就是说不是方法里面的属性),那么这个集合里面的元素是不会自动释放的,因为始终有引用指向它们。所以,如果公用集合里面的某些数据不使用而不去remove掉它们,那么将会造成这个公用集合不断增大,使得系统有内存泄露的隐患。

(33)把一个基本数据类型转为字符串,基本数据类型.toString()是最快的方式、String.valueOf(数据)次之、数据+”"最慢
遇到把一个基本数据类型转为String的时候,优先考虑使用toString()方法。至于为什么,很简单:
String.valueOf()方法底层调用了Integer.toString()方法,但是会在调用前做空判断
Integer.toString()方法就不说了,直接调用了
i + “”底层使用了StringBuilder实现,先用append方法拼接,再用toString()方法获取字符串

(34)使用最有效率的方式去遍历Map
遍历Map的方式有很多,通常场景下我们需要的是遍历Map中的Key和Value,那么推荐使用的、效率最高的方式是:

 1 public static void main(String[] args){
 2     HashMap<String, String> hm = new HashMap<String, String>();
 3     hm.put( "111" , "222" );
 4     Set<Map.Entry<String, String>> entrySet = hm.entrySet();
 5     Iterator<Map.Entry<String, String>> iter = entrySet.iterator();
 6     while (iter.hasNext()){
 7     Map.Entry<String, String> entry = iter.next();
 8     System.out.println(entry.getKey() + " " + entry.getValue());
 9     }
10 }

如果你只是想遍历一下这个Map的key值,那用”Set<String> keySet = hm.keySet();”会比较合适一些。

补充:

  下面是用keySet()和enrtySet()测试两者遍历集合效率的测代码

 1 import java.util.HashMap;
 2 import java.util.Iterator;
 3 import java.util.Map;
 4 
 5 /**
 6  * @Author: jackpotHan
 7  * @Date: 2018/7/18 16:53
 8  * @Description:
 9  */
10 public class MapTest {
11 
12     public static void main(String[] args) {       
13 
14         Map<String,String> keySetMap = new HashMap<>();
15 
16         Map<String,String> entrySetMap = new HashMap<>();
17 
18         for (int i = 0; i < 1000000; i++) {
19             keySetMap.put("" + i, "keySet");
20         }
21         for (int j = 0; j < 1000000; j++) {
22             entrySetMap.put("" + j, "entrySet");
23         }
24 
25         Long startTime1 = System.currentTimeMillis();
26         Iterator<String> keySetIterator = keySetMap.keySet().iterator();
27         while (keySetIterator.hasNext()) {
28             String key = keySetIterator.next();
29             String value = keySetMap.get(key);
30             System.out.println(value);
31         }
32         Long keySetTime = System.currentTimeMillis() - startTime1;
33         long startTime2 = System.currentTimeMillis();
34         Iterator<Map.Entry<String, String>> entryKeyIterator = entrySetMap
35                 .entrySet().iterator();
36         while (entryKeyIterator.hasNext()) {
37             Map.Entry<String, String> e = entryKeyIterator.next();
38             System.out.println(e.getValue());
39         }
40         Long entryTime = System.currentTimeMillis() - startTime2;
41 
42         System.out.println("keySetSpentTime:" + keySetTime);
43         System.out.println("enrtySetSpentTime:" + entryTime);
44 
45     }
46 }
47 //两者耗时对比:
48 //    keySetSpentTime:6509
49 //    enrtySetSpentTime:6477

 

posted @ 2018-09-04 17:25  JackpotHan  阅读(321)  评论(0编辑  收藏  举报