在Java中使用Lambda
最近在工作上用Java的lambda遇到一个小问题,总结归纳一下。 假设一个字符串存着一系列商品的数据:
List<String> data = List.of("Shoes, 12.56", "HairCut, 18.55", "Pat, 129.88", "Music, 21.67");
而现在,设单价20元以上的商品是昂贵的商品,20元以下的商品是便宜的商品。我们希望有一个方法处理这个字符串,统计出来便宜的商品总价是多少,昂贵的商品总价是多少。
首先我们要有个容器来放置这个键值对,这里用一个有意义的Bean很合适
public class Item {
private String name;
private BigDecimal price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
}
如果我们用Java的lambda,很容易就可以写出
Map<String, BigDecimal> res = data.stream()
.map(el -> {
String[] namePricePair = el.split(",");
Item item = new Item();
item.setName(namePricePair[0].trim());
item.setPrice(new BigDecimal(namePricePair[1].trim()));
return item;
}).collect(
Collectors.groupingBy(
item ->
cheapLimit.compareTo(item.getPrice()) > 0 ? "CHEAP": "EXPENSIVE",
Collectors.reducing(BigDecimal.ZERO, item-> item.getPrice(), (init, acc)->init.add(acc))
)
);
Java的ThreadLocal遇到的坑
还是刚刚被分配到项目组的时候,那个时候碰到一个很奇怪的问题,用户A的数据经常和用户B的数据发生混淆,最后在排查代码的时候发现用户相关的数据是从ThreadLocal中取的,而请求的线程池没有将已经过期的用户数据清理掉,才导致了这个现象。
public class Main {
public static void main(String[] args) {
ThreadLocal<String> threadLocal = new ThreadLocal<>();
// use thread pool to demo something
ExecutorService service = Executors.newFixedThreadPool(2);
CompletableFuture[] futures = new CompletableFuture[10];
for(int i = 0; i < 10; i++) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
String threadLocalStr = Thread.currentThread().getName();
if (threadLocal.get() != null) {
System.out.println(threadLocal.get());
} else {
System.out.println("not find in thread local");
threadLocal.set(threadLocalStr);
}
return threadLocalStr;
}, service);
futures[i] = future;
}
CompletableFuture.allOf(futures);
service.shutdown();
}
}
上边这个代码中,ThreadLocal
只有两个值,因为只有两个线程。 所以当使用和线程池时,复用这个线程要清空ThreadLocal