faults on coding (to be continued)

零零散散的在编码过程中犯过一些错误,所以打算专门写一篇总结,持续记录这些错误,以便知错能改。

1 work一直良好的系统中,明显的错误不要改,例如:

1
2
3
4
private int age;
public void setAge(int age){
 age = age;
}

有些功能实际上错上加错的结果,当纠正一个错误的时候,结果就变成了错误。

2 理所当然的思维惯性。

下面的结果是什么?是不是true?

1
2
3
4
5
6
Properties properties = new Properties();
    properties.put("key",true);
     
String valueStr = properties.getProperty("key");
System.out.println(valueStr);
System.out.println(Boolean.TRUE.toString().equalsIgnoreCase(valueStr));

源码分析:
实际上设置的是boolean型的值,然后getProperty返回的是null:

1
2
3
4
5
public String getProperty(String key) {
    Object oval = super.get(key);
    String sval = (oval instanceof String) ? (String)oval : null;
    return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
}

3 针对接口编程和误用方法:

下面的写法试图cache一个值,当不存在对应的value时,自动加载一个值,那下面的值返回什么?

cache loader

1
2
3
4
5
6
7
CacheLoader<String, String> loader = new CacheLoader<String, String>() {
 
    @Override
    public String load(String key) throws Exception {
        return key + "'s value";
    }
};

使用:

1
2
Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize(10_000).expireAfterWrite(15, TimeUnit.MINUTES).build(loader);
String value = cache.getIfPresent("key1");

实际正确的写法

1
2
LoadingCache<String,String> cache = CacheBuilder.newBuilder().maximumSize(10_000).expireAfterWrite(15, TimeUnit.MINUTES).build(loader);
String value = cache.get("key1");

问题出在,一定要仔细阅读API的文档,不要想当然,同时针对接口编程,不定是针对顶层接口编程,如果上来就赋予给顶层接口,则后面的方法选择范围就比较小,可能就不假思考。

4 不假思索的认为某种类型是枚举

在判断响应是否是JSON body时,误以为MediaType.APPLICATION_JSON_TYPE肯定被定义成枚举,所以直接用==判断。

1
MediaType.APPLICATION_JSON_TYPE == response.getMediaType();

修改:不定是每个感觉应该定义成枚举类型的就会定义成枚举类型,另外没有搞清楚状况前,用equals肯定比==更安全,

1
MediaType.APPLICATION_JSON_TYPE.equals(response.getMediaType())

5 Arrays.aslist返回的list?

下面的代码能编译,但是有没有问题?

1
2
List<String> asList = Arrays.asList("123", "456");
asList.removeIf(string -> string.equalsIgnoreCase("123"));

结果:

1
2
3
4
5
Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.AbstractList.remove(AbstractList.java:161)
    at java.util.AbstractList$Itr.remove(AbstractList.java:374)
    at java.util.Collection.removeIf(Collection.java:415)
    at com.github.metrics.Metric.main(Metric.java:29)

源码解析:

1
2
3
4
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a); //此处返回的list是java.util.Arrays.ArrayList<E>,而并不是普通的java.util.ArrayList<E>
}

而这种list的一些实现并未实现:

1
2
3
public E remove(int index) {
    throw new UnsupportedOperationException();
}

思考:可以调用的方法不见得可以work,返回看起来名字一样的,但是不见得是一个。

6 当从list删除元素时,如果从前往后删,则注意有元素删除后,改元素后面的索引以及总的size都已经发生了变化

1
2
3
4
5
6
for (int i = 1; i < list.size(); i++) {
        Element element = list.get(i);
        if(element.getValue()>1){
            list.remove(i);
        }
}

或者:

1
2
3
4
5
6
for (int i = 1; i < list.size(); i++) {
        Element element = list.get(i);
        if(element.getValue()>1){
            list.remove(element);
        }
}

都是坑,所以从后往前删除则没有这个问题。

7 关于lombok的builder注解,成员变量即使设置了默认值,如果builder没有显示设置的话,也不起作用。

1
2
3
4
@Builder
public class IvrCall extends DataTransferObject {
  
    private List<Step> executeTimeStatistics = new ArrayList<>();

当使用builder构建时,没设置executeTimeStatistics,则默认值为null,并不是new ArrayList<>()

8 package.toString vs package.getName 不同

1
2
3
4
5
6
7
8
String packageStr = ZZZ.class.getPackage().toString();
String packageName = ZZZ.class.getPackage().getName();
System.out.println(packageStr);
System.out.println(packageName);
 
 
package com.xxx.yyy
com.xxx.yyy

8 Path大小写问题
9 https://segmentfault.com/q/1010000019170109

发布者

傅, 健

程序员,Java、C++、开源爱好者. About me

发表评论