Java编程珠玑(201903)

1、初始化一个对象的简便方式

Student stu = new Student(){{
	setName("张三");
}};

2、map后去重

List<String> names = list.stream().map(e -> e.getName()).distinct().collect(Collectors.toList());

3、根据某一属性对集合去重

list = list.stream()
				.collect(Collectors.collectingAndThen(Collectors.toCollection(() -> 
								new TreeSet<>(Comparator.comparing(e -> e.getName()))), ArrayList::new));

4、集合排序

// 正序
list = list.stream().sorted((a, b) -> a.getName().compareTo(b.getName())).collect(Collectors.toList());
list = list.stream().sorted(Comparator.comparing(e -> e.getName())).collect(Collectors.toList());
min = list.stream().sorted(Comparator.comparing(e -> e.getName())).findFirst().orElse(null);
// 倒序
list = list.stream().sorted((a, b) -> -(a.getName().compareTo(b.getName()))).collect(Collectors.toList());
list = list.stream().sorted(Comparator.comparing(e -> e.getName()).reversed()).collect(Collectors.toList());
max = list.stream().sorted(Comparator.comparing(e -> e.getName()).reversed()).findFirst().orElse(null);

5、过滤

boolean exists = list.stream().anyMatch(e -> e.getAmount() != null && e.getAmount().compareTo(BigDecimal.ZERO)> 0);

6、集合转换为数组

Long[] ids = list.toArray(new Long[]{});
Long[] ocrFileIds = rows.stream().toArray(Long[] :: new);

7、获取Sum、Count、Max、Min

BigDecimal sum1 = list.stream().map(e -> e.getScore()).reduce((a,b) -> a.add(b)).orElse(BigDecimal.ZERO);
BigDecimal sum2 = list.stream().map(e -> e.getScore()).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);

long count = list.stream().filter(e -> e.getAmount() != null && e.getAmount().compareTo(BigDecimal.ZERO)> 0).count();

Student max = deleteList.stream().max((a, b) -> a.getAmount().compareTo(b.getAmount())).orElse(null);
Student min = deleteList.stream().min((a, b) -> a.getAmount().compareTo(b.getAmount())).orElse(null);

8、Group By 分组

Map<String,List<Student>> map = list.stream().collect(Collectors.groupingBy(e -> e.getName()));

Map<String, Long> collect1 = list.stream().collect(Collectors.groupingBy(e -> e.getName(), Collectors.summingDouble(e -> e.getAmount())));
Map<String, Double> collect2 = list.stream().collect(Collectors.groupingBy(e -> e.getName(), Collectors.averagingDouble(e -> e.getAmount())));
Map<String, Long> collect3 = list.stream().collect(Collectors.groupingBy(e -> e.getName(), Collectors.counting()));
Map<String, Optional<ExpenseInvoice>> collect4 = list.stream().collect(Collectors.groupingBy(e -> e.getName(), Collectors.maxBy((a, b) -> a.getAmount().compareTo(b.getAmount()))));
Map<String, Optional<ExpenseInvoice>> collect5 = list.stream().collect(Collectors.groupingBy(e -> e.getName(), Collectors.minBy((a, b) -> a.getAmount().compareTo(b.getAmount()))));

Map<String, DoubleSummaryStatistics> collect = list.stream().collect(Collectors.groupingBy(e -> e.getName(), Collectors.summarizingDouble(e -> e.getAmount())));
for (Map.Entry<String, DoubleSummaryStatistics> entry : collect.entrySet()) {
    double sum = entry.getValue().getSum();
    double average = entry.getValue().getAverage();
    long count = entry.getValue().getCount();
    double max = entry.getValue().getMax();
    double min = entry.getValue().getMin();
}

9、使用CountDownLatch同时跑多个任务,一起返回

List<File> countFileList = new ArrayList<>();
if (CollectionUtils.isEmpty(countFileList)) {
	return;
}
// 定义线程安全的结果集
List<File> files = Collections.synchronizedList(new ArrayList<>());
// 定义CountDownLatch线程数,有多少个请求,我们就定义多少个
CountDownLatch runningThreadNum = new CountDownLatch(countFileList.size());
for (File file : countFileList) {
    countDownLatchTaskService.getFileBytes(runningThreadNum, file, files);
}
try {
    // 调用CountDownLatch的await方法则当前主线程会等待,直到CountDownLatch类型的runningThreadNum清0
    // 每个任务处理完成会对runningThreadNum减1
    // 如果等待?分钟后当前主线程都等不到runningThreadNum清0,则认为超时,直接中断,抛出中断异常InterruptedException
    runningThreadNum.await(wait, timeUnit);
} catch (InterruptedException e) {
    // 非正常中断应该抛出异常或返回错误结果
    logger.error("CountDownLatch识别线程超时", e);
    throw new ApplicationException(ResponseCode.OVERTIME_FILE_ERROR);
}


// CountDownLatchTaskService.java 核心代码

/**
* 获取文件数据
* @param runningThreadNum 正在运行的线程
* @param file 识别文件
* @param resultList 识别结果列表
*/
@Async("fileBytesExecutor")
public void getFileBytes(CountDownLatch runningThreadNum, File file, List<File> resultList) {
   try{
       // 如果Bytes为空,就自己去取
       CommonService.getFileBytes(file);
       if (file.getSize() <= 0 || ArrayUtils.isEmpty(file.getBytes()) || StringUtils.isEmpty(file.getUrl())) {
           logger.info("文件不存在或文件大小为空或文件Url为空, fileId:::{}, url:::{}, fileSize:::{}", file.getId(), file.getUrl(), file.getSize());
           return;
       }
       resultList.add(file);
   } catch(Exception e) {
       logger.error("获取文件数据出错", e);
   } finally {
       // 当前线程处理完成,runningThreadNum线程数减1,此操作必须在finally中完成,避免处理异常后造成runningThreadNum线程数无法清0
       runningThreadNum.countDown();
   }
}

10、异步任务等待当前事务提交后再执行

// 等待当前事务提交后再处理异步业务,防止数据还未提交导致数据有误
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
     @Override
     public void afterCommit() {
   		 // 异步任务执行
         doAsyncWork();
     }
 });

11、多线程环境下获取时间戳踩坑

在多线程代码中调用System.currentTimeMillis()耗时极慢
在这里插入图片描述
在这里插入图片描述
可见,并发调用System.currentTimeMillis()一百次,耗费的时间是单线程调用一百次的250倍。如果单线程的调用频次增加(比如达到每毫秒数次的地步),也会观察到类似的情况。实际上在极端情况下,System.currentTimeMillis()的耗时甚至会比创建一个简单的对象实例还要多,看官可以自行将上面线程中的语句换成new HashMap<>之类的试试看。

解决方案:

  • 策略一:如果对时间精确度要求不高的话可以使用独立线程缓存时间戳。
  • 策略二:使用Linux的clock_gettime()方法。

策略一实现代码:


public class CurrentTimeMillisClock {	
    private volatile long now;	
    private CurrentTimeMillisClock() {	
        this.now = System.currentTimeMillis();	
        scheduleTick();	
    }	
    private void scheduleTick() {	
        new ScheduledThreadPoolExecutor(1, runnable -> {	
            Thread thread = new Thread(runnable, "current-time-millis");	
            thread.setDaemon(true);	
            return thread;	
        }).scheduleAtFixedRate(() -> {	
            now = System.currentTimeMillis();	
        }, 1, 1, TimeUnit.MILLISECONDS);	
    }	
    public long now() {	
        return now;	
    }	
    public static CurrentTimeMillisClock getInstance() {	
        return SingletonHolder.INSTANCE;	
    }	
    private static class SingletonHolder {	
        private static final CurrentTimeMillisClock INSTANCE = new CurrentTimeMillisClock();	
    }	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值