减少查询数据库的频率,多在内存中计算
在一次请求中,网络IO占据了大多数的时间,代码在内存中的时间是很快的。有时候需要多次查询数据库,这时候可以将一个大的集合查询到,具体使用的时候在进行筛选。尤其避免了在for循环中多次调用数据库查询的情况。举例
错误示范
1 2 3 4 5
| List<Pojo> collection = new ArrayList(); for (Pojo pojo : collection) { Object o = repository.findById(pojo.getId()); xxx }
|
正确示范
1 2 3 4 5 6 7
| List<Pojo> collection = new ArrayList();
List allData = repository.findAll(); for (Pojo pojo : collection) { Optional data = allData.stream().filter(e -> Objects.equals(e.getId(), pojo.getId())).findFirst(); xxx }
|
数据需要精确计算的场景下(如金额,率值,数据分析等)使用java.math.BigDecimal
推荐入参都使用Sring类型的,可以准确的获取预期值,尤其是浮点数,可能无法准确表示一个值,这与二进制有关,而我们使用的是十进制。例如0.1,当构造函数使用double时,传入的值不会正好等于0.1
出参也同样推荐BigDecimal,使用toPlainString()准确的表示。使用toString()可能会出现科学计数法的情况
1 2 3 4 5 6 7 8 9 10 11 12 13
| private static final int DEFAULT_DIV_SCALE = 8;
public static BigDecimal div(String v1, String v2) { return div(v1, v2, DEFAULT_DIV_SCALE); }
public static BigDecimal div(String v1, String v2, int scale) { if (NumberUtil.isNumber(v1) && NumberUtil.isNumber(v2) && new BigDecimal(v2).compareTo(BigDecimal.ZERO) > 0) { return new BigDecimal(v1).divide(new BigDecimal(v2), scale, RoundingMode.HALF_UP); } return BigDecimal.ZERO; }
|
使用枚举判断时,无需使用equals比较,直接使用==
直接使用==也避免了null的判断,枚举的equals实现也是直接==判断的,所以equals等同于==
1 2 3 4 5 6
|
public final boolean equals(Object other) { return this==other; }
|
善用工具类
判断集合是否有元素
通常为list != null && list.size() > 0。可替换为!CollectionUtils.isEmpty(list)更加清晰
判断两个对象的值是否相等
需要判断不为空并且使用equals区比较。可替换为Objects.equals(a, b)
判断两个集合是否相等
许多工具类都提供了API,但并不好用,自己DIY的,也挺好使
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
public static <T>boolean isEqualList(List<T> list1, List<T> list2) { if (list1 == null || list2 == null) { return false; }
if (list1.size() != list2.size()) { return false; }
Set<T> set1 = new HashSet<>(list1); Set<T> set2 = new HashSet<>(list2);
return set1.containsAll(set2) && set2.containsAll(set1); }
|
根据对象属性去重
stream的distinct无法对对象去重(除非每个对象的属性全部相同)。有些时候需要针对于对象的部分属性进行去重,需要使用自定义方法去重
1 2 3 4
| private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) { Map<Object, Boolean> seen = new ConcurrentHashMap<>(); return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; }
|
putIfAbsent()方法是如果key不存在则put如map中,并返回null。若key存在,则直接返回key所对应的value值。
seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
最终表达式如果没有该值会返回true得以保留,有该值会返回false跳过不收集
举个例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class Example { public static void main(String[] args) { List<A> ls = new ArrayList<>(); ls.add(new A("tom","10", "a")); ls.add(new A("jack","20", "b")); ls.add(new A("tom","10", "c")); List<A> collect = ls.stream().filter(distinctByKey(e -> e.getName() + e.getAge())).collect(Collectors.toList()); System.out.println(collect); }
private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) { Map<Object, Boolean> seen = new ConcurrentHashMap<>(); return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; }
} @Data class A { String name; String age; String address; public A(String name, String age, String address) { this.age = age; this.name = name; this.address = address; } }
|
输出结果:[A(name=tom, age=10, address=a), A(name=jack, age=20, address=b)]
小技巧
-XX:+PrintCommandLineFlags可以输出使用的命令(比如最大堆内存之类的)