为了账号安全,请及时绑定邮箱和手机立即绑定

分享几个实用的方法

分享几个实用的方法

神牛步行3---原文地址

  今天主要和大家分享的是本人总结的分页执行方法,也可以说就是分批执行;该篇采用java8新增的表达式来操作,希望能给各位带来好的帮助和在日常工作中提供便利;同样的操作流程和逻辑之前用C#代码写过一次,有需要的朋友可以看以前的博文;

  • 分页方式拆分List为多个子集List方法

  • 执行统一方法-无返回值,关键字:Consumer

  • 执行统一方法-有返回值,关键字:Function

  • 分批并行执行方法 采用:Executors+分页方法

分页方式拆分List为多个子集List方法

  这里我将会分享两种拆分的方法,一种传统subList来分割list数据,一种采用stream流来拆分;先来看第一种整体代码:

复制代码

 1 /** 2      * list 分成多个子集list 3      * @param list 4      * @param pageCount 总页数 ,如果list条数不够,根据list条数来 5      * @param <T> 6      * @return 7      */ 8     public static <T> List<List<T>> funcToPage(List<T> list, int pageCount) { 9 10         int currentCount = list.size();11         //总页数 真实线程数12         int page = pageCount >= currentCount ? currentCount : pageCount;13         //每页条数14         int pageSize = currentCount / page;15 16         List<List<T>> pageList = new ArrayList<>();17         for (int i = 0; i < page; i++) {18             //subList分页19             List<T> lastT = new ArrayList<>();20             //分页部分21             lastT.addAll(list.subList(i * pageSize, (i + 1) * pageSize));22 23             //把剩余部分没拆到每批次中24             if (page * pageSize + i < currentCount) {25                 lastT.addAll(list.subList(page * pageSize + i, page * pageSize + i + 1));26             }27 28             pageList.add(lastT);29         }30         return pageList;31     }

复制代码

  这里通过按分页的方式来分割list数据,分页几乎是每个系统都会用到的方式;再来看看新特性分割的方法:

复制代码

 1 public static <T> List<List<T>> funcToPage(List<T> list, int pageCount) { 2  3         int currentCount = list.size(); 4         //总页数 真实线程数 5         int page = pageCount >= currentCount ? currentCount : pageCount; 6         //每页条数 7         int pageSize = currentCount / page; 8  9         List<List<T>> pageList = new ArrayList<>();10         for (int i = 0; i < page; i++) {11 12             //采用流方式分页13             List<T> lastPage = list.stream().14                     skip(i * pageSize).15                     limit(pageSize).16                     collect(Collectors.toList());17 18             if (page * pageSize + i < currentCount) {19                 lastPage.add(20                         list.stream().21                                 skip(page * pageSize + i).22                                 limit(1).23                                 findFirst().24                                 get()25                 );26             }27             pageList.add(lastPage);28         }29         return pageList;30     }

复制代码

  通过stream流蓝分割,这里用到了skip(),limit()两个方法来分页,这两方法分别表示:跳到某条数据开始和限制多少条数据,最后有个findFirst()方法表示:查找第一条数据,看起来和C#的linq写法类似;

执行统一方法-无返回值,关键字:Consumer

  这里要分享的关于list(当然也可以是其他)数据循环执行某个方法,这里用到了Consumer提供的accept方法来接受参数,代码如下:

复制代码

1 /**2      * list 不返回值3      * @param list     数据源4      * @param consumer5      * @param <T>      参数类型6      */7     public static <T> void funcToNoResult(List<T> list, Consumer<T> consumer) {8         list.forEach(b -> consumer.accept(b));9     }

复制代码

  测试用例:

1  List<Integer> list = Arrays.asList(1, 2, 3);2  FuncUtil.funcToNoResult(list, b -> {3      System.out.println("funcToNoResult这是:" + b);4  });

  https://img1.sycdn.imooc.com//5afd85710001814003640099.jpg

执行统一方法-有返回值,关键字:Function

  和上面一样这个方法也主要是对list数据在某个表达式中操作,但是该方法有返回值的概念,就是说先通过执行了表达式后,能够得到执行的返回结果:

复制代码

 1  /** 2      * list 有返回值 3      * @param list     数据源 4      * @param function 5      * @param <T>      参数类型 6      * @param <V>      返回类型 7      * @return 8      */ 9     public static <T, V> List<V> funcToResult(List<T> list, Function<T, V> function) {10         List<V> results = new ArrayList<>();11         list.forEach(b -> results.add(function.apply(b)));12         return results;13     }

复制代码

  关键字Function,要得到返回值主要是通过function.apply(b)方法来获取,如下测试用例:

1 FuncUtil.funcToResult(list, b -> {2      return "funcToResult这是:" + b;3 }).forEach(b -> System.out.println(b));

  https://img1.sycdn.imooc.com//5afd85860001374c03000104.jpg

分批并行执行方法 采用:Executors+分页方法

   这里来到今天分享的重点,该方法主要可拆分为以下几个步骤:分批数据源-》分批并行执行-》合并结果;分配数据采用的就是上面的分页方法,下面具体看代码:

复制代码

 1 /** 2      * 分批执行方法 采用:Executors+分页方法 3      * @param list           数据源 4      * @param function       处理方法 lamda表达式 5      * @param maxThreadCount 处理线程数量 6      * @param <T>            参数类型 7      * @param <V>            返回类型 8      * @return 处理完成结果集 9      */10     public static <T, V> List<V> funcToExecutorPageSubmits(List<T> list, Function<T, V> function, int maxThreadCount) {11         List<V> results = new ArrayList<>();12 13         if (list == null || list.isEmpty()) {14             return results;15         }16 17         maxThreadCount = maxThreadCount <= 0 ? 1 : maxThreadCount;18         maxThreadCount = maxThreadCount >= 10 ? 10 : maxThreadCount;19 20         //分批数据源21         List<List<T>> pageList = funcToPage(list, maxThreadCount);22 23         //分批并行执行24         List<Future<List<V>>> futures = new ArrayList<>();25         ExecutorService executorService = Executors.newFixedThreadPool(pageList.size());26         pageList.forEach(items -> {27             futures.add(28                     executorService.submit(() -> {29                         List<V> childResults = new ArrayList<>();30                         items.forEach(item -> childResults.add(function.apply(item)));31                         return childResults;32                     })33             );34         });35 36         //合并结果37         futures.forEach(b -> {38             try {39                 results.addAll(b.get());40             } catch (InterruptedException e) {41                 e.printStackTrace();42             } catch (ExecutionException e) {43                 e.printStackTrace();44             }45         });46 47         return results;48     }

复制代码

  并行执行就是用了ExecuteService+Future来接受结果,通过executorService.submit()提交执行某一批次数据需要执行的方法,最后再汇总结果;

  因为有这种常见的场景:某一批数据或者url需要在执行某个按钮事件时去调用第三方接口并同步返回数据给界面用户,因此就有了上面方法的设计和产生。就目前该方法已被我用在了生产环境中,暂无什么异常或者问题;以下是测试用例:

复制代码

 1 List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8); 2 FuncUtil.funcToExecutorPageSubmits( 3        //数据源 4        list  
 5        , 6        //待执行方法 7        b -> { 8                return Thread.currentThread().getName() + ":" + b; 9        },10        6).11         //输出返回结果12       forEach(b -> System.out.println(b));

复制代码

  https://img1.sycdn.imooc.com//5afd85ab0001e9dd04020234.jpg


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消