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