消除代码里的坏味道

笔记
280 0

消除代码里的坏味道

之前我自己使用的一直都是Spring提供的属性copy工具类,Apache的没用过,性能真的很差吗,直接上代码吧

     /**
     * 雨燕框架规定:
     * 【强制】 避免用 Apache Beanutils 进行属性的 copy。说明: Apache BeanUtils 性能较差。
     * <p>
     * 几种属性copy方式性能对比
     * 1.cglib BeanCopier
     * 2.spring BeanUtils.copyProperties
     * 3.apache PropertyUtils
     * 4.apache BeanUtils
     */
    @Test
    public void testCope() {
  Map<String, Object> map = Maps.newHashMap();
    UserVo userVo = new UserVo()
            .setUserName("cq")
            .setAge(10)
            .setId(1L)
            .setEmail("6@6.srl");
    long l1 = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        UserEntity entity = new UserEntity();
        BeanUtil.copyProperties(userVo, entity);
    }
    map.put("hutool cglib", System.currentTimeMillis() - l1);

    long l2 = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        UserEntity entity = new UserEntity();
        BeanUtils.copyProperties(userVo, entity);
    }
    map.put("spring", System.currentTimeMillis() - l2);

    long l3 = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        UserEntity entity = new UserEntity();
        try {
            org.apache.commons.beanutils.PropertyUtils.copyProperties(entity, userVo);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    map.put("apache PropertyUtils", System.currentTimeMillis() - l3);

    long l4 = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        try {
            UserEntity entity = new UserEntity();
            org.apache.commons.beanutils.BeanUtils.copyProperties(entity, userVo);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    map.put("apache BeanUtils", System.currentTimeMillis() - l4);
    System.out.println("result:" + JSON.toJSONString(map));
}

结论:通过几次测试我们发现,在copy的次数少量的情况下,目前几款属性copy都是可以用的,性能都不错,但是copy次数多的情况下,spring和cglib的性能要比Apache要高。但是雨燕框架entity里面不支持驼峰,需要对每个字段单独处理,还是比较费劲的,所以暂时还是不建议使用属性copy工具。

4.异步操作必须用线程池吗

一般我们开始一个异步的操作直接使用的是线程池,JAVA8在JUC工具类给我们提供了更好用的CompletableFuture,直接来看使用吧。

4.1 常用的api:

1.CompletableFuture.supplyAsync() 创建异步线程方式一 需要返回值
2.CompletableFuture.runAsync() 创建异步线程方式二 不需要返回值 这种方式不会输出异常信息,需要自己处理
3.thenApply() 把上个输出流变成输入流进入
4.thenAccept() 拿到输出结果进行处理
5.get();拿到返回结果
6.CompletableFuture.supplyAsync(() -> do(), executor) 使用我们自己创建的线程池,非自带的ForkJoinPool.commonPool()

4.2 上面的api工作中已经差不多够用了,下面是其他的api,感兴趣可以了解下 -.-

7.allOf().join(); 线程走到这里会暂停直到取到所有的future结果
8.thenCompose方法允许你对两个异步操作进行流水线,第一个操作完成时,将其结果作为参数传递给第二个操作
9.whenComplete((v, e)->) v是上个流水线返回值,e输出异常信息
10.handle() 对上个流水线返回值处理
....

4.3 其他

这里单独说下异步操作使用自己的线程池 -> CompletableFuture.supplyAsync(() -> do(), executor)
简单介绍:ForkJoinPool 是java8默认的公用共享线程池。
异步操作supplyAsync()和runAsync(), 集合stream并发流操作 parallelStream().forEach(),默认用的都是这个。
不是为了替代ExecutorService,而是它的补充,在某些应用场景下性能比ExecutorService更好。
核心是分治算法实现,适合的是计算密集型任务。
构造源码:{@link ForkJoinPool#makeCommonPool()} ()}
(parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
默认创建的线程数是当前机器核心数-1,但是可以手动设置:
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20");

ForkJoinPool原理:

1) ForkJoinPool 的每个工作线程都维护着一个工作队列(WorkQueue),这是一个双端队列(Deque),里面存放的对象是任务(ForkJoinTask)。
2) 每个工作线程在运行中产生新的任务时,会放入工作队列的队尾,并且工作线程在处理自己的工作队列时,使用的是 LIFO(后进先出) 方式,也就是说每次从队尾取出任务来执行。
3) 每个工作线程在处理自己的工作队列同时,会尝试窃取一个任务执行。
4) 在既没有自己的任务,也没有可以窃取的任务时,进入休眠。

    @Test
    @SneakyThrows
    public void testSyncCompletableFuture() {
        // 1.查询用户信息
        Optional<UserEntity> userInfoBetter = this.getUserInfoBetter(new UserVo());
        Long userId = userInfoBetter
                .map(UserEntity::getId)
                .orElseThrow(() -> new RuntimeException("用户不存在!"));
     // 2.根据用户ID异步查询会员信息,然后再根据会员信息查询优惠信息
    // 2.1 supplyAsync()
    // thenApply()
    // thenAccept()
    CompletableFuture
            .supplyAsync(() -> this.findVipInfo(userId))
            .thenApply(vipInfoDto -> this.findDiscount(vipInfoDto.getId()))
            .thenAccept(disDto -> this.checkDiscountInfo(disDto.getId()));

    // 2.2 runAsync()
    CompletableFuture.runAsync(() -> this.findVipInfoNoReturn(userId));

    // 2.3 get()
    CompletableFuture<VipInfoDto> future = CompletableFuture
            .supplyAsync(() -> this.findVipInfo(userId));
    VipInfoDto vipInfoDto = future.get();
    this.findDiscount(vipInfoDto.getId());

    // 2.4 使用自己的线程池
    CompletableFuture<VipInfoDto> future2 = CompletableFuture
            .supplyAsync(() -> this.findVipInfo(userId), executor);
    future2.get();
}

5.一些"好玩的"注解

  1. 链式注解 @Accessors(chain = true) 这个比较常用 ---- 写在实体类上
  2. 我们不想用new来创建对象了 可以用自定义创建对象注解 @RequiredArgsConstructor(staticName = "of") ---- 写在实体类上,一般这种写法用在返回前端封装的对象上面
  3. @RequiredArgsConstructor的高级玩法
    有时候我们一个serviceImpl里面会写很多@Autowired注解自动注入,能不能不写?可以!在serviceImpl层加上面的注解就OK! @RequiredArgsConstructor(onConstructor=@__(@Autowired)) 需要注意的是被注入的对象必须final修饰, 该注解了解下即可 -.-
  4. @Builder注解 直接用.属性名来赋值,代替set
   @Override
    public void annotationTest() {
        // 一般写法
        UserEntity entitySimple = new UserEntity();
        entitySimple.setId(1L);
        entitySimple.setAge(10);
        entitySimple.setUser_name("cq");
        System.out.println("entitySimple:" + JSON.toJSONString(entitySimple));
  
    // @Accessors
    UserEntity entity = new UserEntity()
            .setId(1L)
            .setAge(10)
            .setUser_name("cq");
    System.out.println("entity:" + JSON.toJSONString(entity));
  
    // @RequiredArgsConstructor(staticName = "of")
    ShareResult shareResult = ShareResult.of().setCode(0).setMessage("OK!");
    System.out.println("shareResult:" + JSON.toJSONString(shareResult));

    // @RequiredArgsConstructor(onConstructor = @__(@Autowired))
    List<User> all = userService.findAll();
    System.out.println("allUsers:" + JSON.toJSONString(all));

    // @Builder
    UserEntity buildUser = UserEntity
            .builder()
            .id(2L)
            .user_name("cq")
            .build();
    System.out.println("buildUser:" + JSON.toJSONString(buildUser));
}

6.总结

今天分享的这些主要是java8的一些新特性和lombok注解,工作中可能用的上可能用不上,反正了解下也是好的嘛,不对的地方欢迎大家指正交流

最后更新 2021-09-06
评论 ( 0 )
评论已关闭