Lombok

1、使用Lombok时Jackson无法识别单字母+大写首字母单词的字段,类似:iPhone,这种字段要改成全小写才能反序列化。具体的可以看看序列化的结果。

2、当使用继承时,equals不会将父类的字段参与比较。

  • 需要加上此注解:@EqualsAndHashCode(callSuper = true)

SimpleDateFormat

一般我们使用SimpleDateFormat的时候会把它定义为一个静态变量,避免频繁创建它的对象实例。

单线程场景使用时没有问题,多线程场景下使用时会报错:java.lang.NumberFormatException: multiple points

此外,SimpleDateFormat和它继承的DateFormat类也不是线程安全的。

  • 可以解析大于/等于他定义的时间精度,但不能解析小于它定义的时间精度。

解决方案

低效方案

1、使用临时变量的形式:即每次都生成一个对象,缺点是==低效,创建大量的临时对象==。

2、使用synchronized关键字,缺点是==降低了并发性,大量并发时进程阻塞,而且使用这个的一般是工具类,这是及其不友好的。

高效方案

1、使用Threadlocal

ThreadLocal可以确保每个线程都可以得到单独的一个SimpleDateFormat的对象。

private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() {
    @Override
    protected DateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    }
};

public static Date parse(String dateStr) throws ParseException {
    return threadLocal.get().parse(dateStr);
}

public static String format(Date date) {
    return threadLocal.get().format(date);
}

2、使用 DateTimeFormatter

public class SimpleDateFormatTest {

    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public static String formatDate2(LocalDateTime date) {
        return formatter.format(date);
    }

    public static LocalDateTime parse2(String dateNow) {
        return LocalDateTime.parse(dateNow, formatter);
    }
}

hashCode和equals必须同时编写

1、集合中元素的索引与equals方法相关。

  • 类实现了compareTo方法,就需要实现equals方法。
  • 两者实现过程需要需要同步,否则会出现不一致的情况。
public class EqualsOrElse {
    private static class User implements Comparable<User> {
        private String name;
        private Integer age;

        public User(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        @Override
        public boolean equals(Object o) {
            if (o instanceof User) {
                return this.name.equals(((User) o).getName());
            }
            return false;
            // return this.age - ((User) o).age == 0;
        }

        @Override
        public int hashCode() {
            return Objects.hash(name, age);
        }

        @Override
        public int compareTo(User o) {
            return this.age - o.age;
        }

    }

    public static void test02(){
        List<User> users = new ArrayList<>();
        User us1 = new User("xiaoming", 20);
        User us2 = new User("xiaoming", 22);
        users.add(us1);
        users.add(us2);

        User user = new User("xiaoming",22);

        System.out.println(users.indexOf(user)); // 基于equals:返回true
        System.out.println(Collections.binarySearch(users, user)); // 基于compareTo:返回0

    }

    public static void main(String[] args) {
        test02();
    }
}

2、hashCode方法一定要编写,否则集合存储时可能会出现问题

public class EqualsOrElse {
    private static class User {
        private String name;
        private Integer age;

        public User(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        @Override
        public boolean equals(Object o) {
            if(o instanceof User){
                return this.name.equals(((User) o).getName());
            }
            return false;
        }

        @Override
        public int hashCode() {
            return Objects.hash(name, age);
        }
    }

    public static void main(String[] args) {
        User us1 = new User("xiaoming",22);
        User us2 = new User("xiaoming",22);

        Set<User> userSet = new HashSet<>();
        Map<User,Integer> userMap = new HashMap<>();

        userSet.add(us1);
        userSet.add(us2);
        System.out.println(userSet.size()); // 2
        userMap.put(us1,1);
        userMap.put(us2,2);
        System.out.println(userMap.size()); // 2
        // 分析:两个对象参数一致,即认为是相等的,但是上面两个集合军存储了两份,这是不对的
        // 原因:没有编写hashCode导致的,而Set和Map在存储时都需要用到hashcode值
        // 解决:编写hashCode方法,并且要求所有参数都参与运算
    }
}

BigDecimal精度问题

1、设置的精度必须必原值的精度大,如果比原值小的话需要设置舍入规则。

2、除法的结果需要设置精度,不设置精度和舍入规则,遇到无法除尽的问题就会报错。

3、数值比较时需要精度匹配,否则就会出现0.0!=0的情况。

  • equals:结果错误【精度不相同直接返回false】
  • compareTo:结果正确
  • 所以尽量不要使用使用BigDecimalequals去比较大小。

避免抽象类和接口的选择失误

1、共性,有状态的属性用抽象类去表达

2、特有的独立的属性用独立的接口去实现

Lambda

1、使用Lambda表达式的前提,必须有==函数式接口==,只能有一个抽象方法,但可以有多个非抽象方法的接口

  • @FunctionalInterface
@FunctionalInterface
interface IFindWord{

    String find(String time);
  
}
public static void main(String[] args) {
    Map<String,String> x = new HashMap<>();
    x.put("1","a");
    x.put("2","b");
    IFindWord iFindWord = x::get; // :: 方法引用  lambda的语法糖
    System.out.println(iFindWord.find("1"));
}

2、迭代次数非常多,每一步都会产生中间结果,产生的结果会存在JVM内存中,开销非常大。

public static void main(String[] args) {
    List<String> names = Arrays.asList("xiaoming","xixixix","fsdfsdfsd");
    int longMaxName = names.stream()
        .filter(s->{
            System.out.println("filter:"+s);
            return s.startsWith("x");
        }).mapToInt(n->{
        System.out.println("mapToInt:"+n);
        return n.length();
    }).max().getAsInt();
    System.out.println(longMaxName);
}
/*
filter:xiaoming
mapToInt:xiaoming
filter:xixixix
mapToInt:xixixix
filter:fsdfsdfsd
8
*/

FastJSON

当对象中的字段使用同一个别名时,转换会随机将字符串中的这个值转到这两个字段中的一个上。

BeanPostProcessor

特性

  • Bean后置处理器
  • 两个回调方法
    • postProcessBeforeInitialization:每一个Bean对象==初始化==之前回调。
    • postProcessAfterInitialization:每一个Bean对象==初始化==之后回调。
  • 在Bean==实例化==之后执行