Java编码坏习惯改进

Java编码坏习惯改进

总结自公众号:阿里技术,一方面做笔记,一方面觉得很有道理分享出来。

让性能更高

1.需要 Map 的主键和取值时,应该迭代 entrySet()
需要同时使用map的key和value取值时,迭代 entrySet()才是更高效的方法。比起先获取KeySet再迭代获取value性能更好,因为get方法是先根据key获取Node,再取得Node的value值。

反例:
Map<String, String> map = ...;
for (String key : map.keySet()) {
	String value = map.get(key);    
	...
}
正例:
Map<String, String> map = ...;
for (Map.Entry<String, String> entry : map.entrySet()) {    
    String key = entry.getKey();    
    String value = entry.getValue();    
    ...
}

2.使用Collection.isEmpty()检测空

Collection.isEmpty() 实现复杂度都是O(1), 但某些Collection.size()实现的复杂度是O(n)(说实话,哪些Collection的复杂度是O(n)的, 作者没有找到,读者评论能提示一下么,C++我知道mingw和msvc的库实现中size是这样的,但java中还没有看到过);

3.集合初始化尽量指定大小

集合是有容量的,一旦超过,就需要扩容和复制,为了减少扩容和复制,尽量指定大小。

4.字符串拼接使用StringBuilder

一般的字符串拼接会在编译器就行优化,但是在循环中的字符串拼接,java编译无法做到优化(why?),所以使用StringBuilder替换。

反例:
String s = "";
for (int i = 0; i < 10; i++) {    
    s += i;
}
正例:
String a = "a";
String b = "b";
String c = "c";
String s = a + b + c; // 没问题,java编译器会进行优化
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; i++) {    
    sb.append(i);  // 循环中,java编译器无法进行优化,所以要手动使用StringBuilder
}

5.list的随机访问

当获取到的对象是List时,我们不能知道它的内部具体是数组还是链表,而数组的随机访问很简单,链表则需要一个个逐个访问,如何判断数组还是链表?可以判断他是否实现RandomAccess接口。

// 调用别人的服务获取到
listList<Integer> list = otherService.getList();
if (list instanceof RandomAccess) {    
    // 内部数组实现,可以随机访问    
    System.out.println(list.get(list.size() - 1));
} 
else {    
    // 内部可能是链表实现,随机访问效率低
}

6.频繁调用Collections.contains方法请使用set

List的contains方法时间复杂度是O(n)的,如果需要频繁调用,最好将list转化为HashSet,那样的复杂度是O(1)的。

ArrayList<Integer> list = otherService.getList();
Set<Integer> set = new HashSet(list);
for (int i = 0; i <= Integer.MAX_VALUE; i++) {    
    // 时间复杂度O(1)    
    set.contains(i);
}

让代码更优雅

1.特殊数据类型在后面跟上类型标记

如使用长整形时,后面加上L,必须大写,小写容易和1混淆。

long value = 1L;
long max = Math.max(1L, 5L);

2.不要使用魔法值

魔法值容易使代码的意义变得不明确,也许你编码时很清楚,但是过了很久,容易迷惑。

反例:
for (int i = 0; i < 100; i++){    
...
}
if (a == 100) {    
...
}
正例:
private static final int MAX_COUNT = 100;
for (int i = 0; i < MAX_COUNT; i++){    
    ...
}
if (count == MAX_COUNT) {    ...}

3.建议使用try-with-resources语句

java7中引入了这个语法糖,这个语句能保证资源自动关闭,比起原来的try-catch-finally简洁不少。

反例:
private void handle(String fileName) {    
    BufferedReader reader = null;    
    try {        
        String line;        
        reader = new BufferedReader(new FileReader(fileName));        
        while ((line = reader.readLine()) != null) {            
            ...        
        }   
    } catch (Exception e) 
    {        
        ...    
    } finally 
    {        
        if (reader != null) {            
            try {                
                reader.close();            
            } catch (IOException e) {                
                ...            
              }        
        }    
    }
}
正例:
private void handle(String fileName) {    
    try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {        		String line;        
       while ((line = reader.readLine()) != null) {            
             ...        
       }    
    } catch (Exception e) {       
        ...    
    }
}

4.删除多余无用的代码,字段,括号和参数。

5.工具类应该屏蔽构造函数

工具类是一堆静态字段和函数的集合,不应该被实例化,为了防止别人使用错误,应该屏蔽构造函数。

正例:
public class MathUtils {    
    public static final double PI = 3.1415926D;    
    private MathUtils() {}    
    public static int sum(int a, int b) {        return a + b;    }
}

6.公有静态常量应该使用类访问,而不要使用类的实例来访问。

7.不要使用NullPointerException来判断空

空指针异常应该用代码规避(比如检测不为空),而不是用捕获异常的方式处理。

反例:
public String getUserName(User user) {    
    try {        
        return user.getName();    
    } catch (NullPointerException e) {        
        return null;    
    }
}
正例:
public String getUserName(User user) {    
    if (Objects.isNull(user)) {        return null;    }    
    return user.getName();
}

8.使用String.valueOf(value)代替“”+value

当要把其它对象或类型转化为字符串时,使用 String.valueOf(value) 比""+value 的效率更高。

9.过时的代码使用@Deprecated注解注明


让代码远离bug

1.不要使用构造方法BigDecimal(double)

BigDecimal(double) 存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常。

反例:
BigDecimal value = new BigDecimal(0.1D); *// 0.100000000000000005551115...* 
正例:
BigDecimal value = BigDecimal.valueOf(0.1D);; // 0.1

2.返回空数组和空集合而不是null

返回null,需要调用方检测null,否则会抛出异常,返回空数组和空集合,可以有效避免,并且让代码更简洁。

反例:
public static List<Result> getResultList() {    return null;}
正例:
public static List<Result> getResultList() {    return Collections.emptyList();}

3.优先使用常量或者确定值来调用equeals方法

对象的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals 方法。当然,使用 java.util.Objects.equals() 方法是最佳实践。

反例:
public void isFinished(OrderStatus status) {    
    // status可能为空,导致异常
    return status.equals(OrderStatus.FINISHED); // 可能抛空指针异常 
}
正例:
public void isFinished(OrderStatus status) {    
    return OrderStatus.FINISHED.equals(status);
}

public void isFinished(OrderStatus status) {    
    return Objects.equals(status, OrderStatus.FINISHED);
}

4.小心使用String.split(String regex)

String的split,传入的分割符是正则表达式,部分关键字,如(.|)需要转义

反例:
"a.ab.abc".split("."); // 结果为[]"a|ab|abc".split("|"); // 结果为["a", "|", "a", "b", "|", "a", "b", "c"]
正例:
"a.ab.abc".split("\\."); // 结果为["a", "ab", "abc"]
"a|ab|abc".split("\\|"); // 结果为["a", "ab", "abc"]

5.枚举的属性字段必须是私有不可变的

枚举通常被当做常量使用,如果枚举中存在公共属性字段或设置字段的方法,会导致枚举常量的属性值很容易被修改。理想情况下,枚举类型的属性字段是私有的,并且在私有构造函数中赋值,没有对应的setter方法,最好加上final修饰符。

反例:
public enum UserStatus {    
    DISABLED(0, "禁用"),    ENABLED(1, "启用");    
    public int value;    
    private String description;    
    private UserStatus(int value, String description) {        
        this.value = value;        
        this.description = description;    
    }    
    public String getDescription() {        
        return description;    
    }    
    public void setDescription(String description) {        
        this.description = description;    
    }
}
正例:
public enum UserStatus {    
    DISABLED(0, "禁用"),    ENABLED(1, "启用");    
    private final int value;    
    private final String description;    
    private UserStatus(int value, String description) {        
        this.value = value;        
        this.description = description;    
    }    
    public int getValue() {        
        return value;    
    }    
    public String getDescription() {        
        return description;    
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值