精华内容
下载资源
问答
  • Java 8 流式编程实例

    2021-02-23 17:22:21
    Java 8 流式编程实例 集合过滤 //过滤不为空的对象并收集到一个集合中 contentList.stream().filter(p -> p.getPunishContent() != null).collect(Collectors.toList()); 集合分组 //list集合中的数据 按...

    1. 集合过滤
    //过滤不为空的对象并收集到一个集合中
    contentList.stream().filter(p -> p.getPunishContent() != null).collect(Collectors.toList());
    
    1. 集合分组
    //list集合中的数据 按某个字段分组
    Map<String, List<OperPunishReportDto>> collect = contentList.stream()
                    .filter(p -> p.getPunishContent() != null)
                    .collect(Collectors.groupingBy(OperPunishReportDto::getDutyCode));
    
    1. 去除List集合中对象的某个字段为集合
    List<Object> content = operPunishReportDtos.stream()
                        .filter(p -> p.getPunishContent() != null)
                        .map(OperPunishReportDto::getPunishContent)
                        .collect(Collectors.toList());
    
    1. List集合中某字段求和
    //BigDecimal 类型求和
    BigDecimal account = linkedHashMaps1.stream()
                                .map(p -> BigDecimal.valueOf((Integer) p.get("amount")))
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
    //int、double、long
    double max = list.stream().mapToDouble(User::getHeight).sum();
    
    1. List集合转为Map
    //指定按某个字段为key 对象本身为value 
    //Function.identity() 固定写法,指定对象本身为value 
    //(key1,key2)->key2) key相同时使用key2覆盖key1
    Map<String, OperCenterReachDto> resultMap = list.stream()
                    .collect(Collectors.toMap(OperCenterReachDto::getWaybillNo, Function.identity(),(key1,key2)->key2));
    
    展开全文
  • 其实Java流式编程是java8的新特性了.现在JDK都出到15了…当然JDK15不是长期支持版本,最新的长期支持版本是Java11,而下一个长期支持版本要等到2021年9月发布的Java17. 一、什么是Stream Stream中文称为”流”,通过...

    java8流式编程,你值得拥有!

    其实Java流式编程是java8的新特性了.现在JDK都出到15了…当然JDK15不是长期支持版本,最新的长期支持版本是Java11,而下一个长期支持版本要等到2021年9月发布的Java17.

    一、什么是Stream

    Stream中文称为”流”,通过将集合转换为”流”的元素序列,通过声明性方式,能够对集合中的每个元素进行一系列并行或串行的流水线操作.

    二、流操作

    ![image.png](https://img-blog.csdnimg.cn/img_convert/84463b71a829cd0470734839acc94de0.png#align=left&display=inline&height=137&margin=[object Object]&name=image.png&originHeight=186&originWidth=749&size=19584&status=done&style=none&width=552)
    整个流操作就是一条流水线,将元素放在流水线上一个个地进行处理
    其中数据源就是原始集合,然后将如List的集合转换为Stream类型的流,并对流进行一系列的中间操作,比如过滤保留部分元素,对元素进行排序、类型转换等;最后再进行一个终端操作,可以把Stream转换回集合类型,也可以直接对其中的各个元素进行处理,比如打印、计算总数、计算最大值等等.
    很多流操作本身就会返回一个流,所以多个操作可以直接连接起来:
    ![image.png](https://img-blog.csdnimg.cn/img_convert/42047953184020be69151b8058adacd5.png#align=left&display=inline&height=126&margin=[object Object]&name=image.png&originHeight=193&originWidth=967&size=63607&status=done&style=none&width=630)
    如果是以前,进行这么一系列操作,你需要做个迭代器或者foreach循环,然后遍历,一步步亲历亲为地去实现这些操作.但是如果使用流,你便可以直接声明式地下指令,流会帮你完成这些操作.
    这就像SQL语句一样,select username from user where id = 1,你只要说明:”我需要id是1(id = 1)的用户(user)的用户名(username)”,那么就可以得到自己想要的数据,而不需要自己亲自去数据库里面循环遍历查找.

    三、项目实际应用

    功能概述:现在有一个接口需要查询出数据库用户所在的数据源的未授权的表. 未授权的表=已落地的表-已授权的表.
    假如已落地的表list1简化为{1,2,3,4,5,6,7,8,9},已授权的表list2简化为{2,4,5,8},那么未授权的表list3就应该是{1,3,6,7,9}
    如果不用流式编程,那么就需要遍历list1和list2,然后判断一下list1的值是否有等于list2的值的,是的话就把该值remove.
    用流式编程只需要一行代码:

    list1.stream().filter(x -> !list2.contains(x)).collect(Collectors.toList());
    

    简单说明一下:首先把集合list1转换为stream(流),然后进行过滤,filter会保留判断条件为true的记录.x ->这里的x也可以写成a,b,c之类的,起到的作用是记录list1流中的数据. 最后的collect是把流收集起来,Collectors.toList()是把收集的流转换成list集合返回.
    在使用过程中,对于某些关键步骤,可以考虑使用函数引用来替代复杂的、多个语句的 lambda 表达式,用函数名简单描述要做的事情.这里给出个例子:

    public void refactorAfter() {
        List<Student> studentLists = getStudents();
        // output: Student{name=xiaoming, age=21, score=100}
       studentLists.stream().filter(this::filterStudents).forEach(System.out::println);
    }
    private boolean filterStudents(Student student) {
        // 过滤出年龄大于20岁并且分数大于95的学生
        return student.getAge() > 20 && student.getScore() > 95;
    }
    

    总结:流式编程可以极快地处理多个集合的相关操作,大大提高了开发效率.在你有了一定了解后可阅读性也是大大提高的

    展开全文
  • ##Stream中间是怎么执行的 java8流式编程 如果Stream只有中间操作是不会执行的,当执行终端操作的时候才会执行中间操作,这种方式称为延迟加载或惰性求值。多个中间操作组成一个中间操作链,只有当执行终端操作的时候才...

    ##Stream中间是怎么执行的 java8流式编程
    如果Stream只有中间操作是不会执行的,当执行终端操作的时候才会执行中间操作,这种方式称为延迟加载或惰性求值。多个中间操作组成一个中间操作链,只有当执行终端操作的时候才会执行一遍中间操作链,具体是因为什么我们在后面再说明。下面看下Stream有哪些中间操作。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • JAVA8流式编程【4】——如何替代FOR循环 2018年05月08日 20:10:25 fisher虞 阅读数:1467 ...

    JAVA8流式编程【4】——如何替代FOR循环

    尽管 for 循环包含许多可变部分,但许多开发人员仍非常熟悉它,并会不假思索地使用它。从 Java™ 8 开始,我们有多个强大的新方法可帮助简化复杂迭代。在本文中,您将了解如何使用 IntStream 方法 rangeiterate 和 limit 来迭代范围和跳过范围中的值。您还将了解新的 takeWhile 和 dropWhile 方法(即将在 Java 9 中引入)。


    在 Java 语言的第 1 个版本中就开始引入了传统的 for 循环,它的更简单的变体 for-each 是在 Java 5 中引入的。大部分开发人员更喜欢使用 for-each 执行日常迭代,但对于迭代一个范围或跳过范围中的值等操作,他们仍会使用 for

    for 循环的麻烦

    for 循环非常强大,但它包含太多可变部分。甚至在打印 get set 提示的最简单任务中,也可以看出这一点:

    清单 1. 完成一个简单任务的复杂代码
    System.out.print("Get set...");
       for(int i = 1; i < 4; i++) {
         System.out.print(i + "...");
       }

    在清单 1 中,我们从 1 开始循环处理索引变量 i,将它限制到小于 4 的值。请注意,for 循环需要我们告诉循环是递增的。在本例中,我们还选择了前递增而不是后递增。

    清单 1 中没有太多代码,但比较繁琐。Java 8 提供了一种更简单、更优雅的替代方法:IntStream 的 range 方法。以下是打印清单 1 中的相同 get set 提示的 range方法:

    清单 2. 完成一个简单任务的简单代码
    System.out.print("Get set...");
       IntStream.range(1, 4)
         .forEach(i -> System.out.print(i + "..."));

    在清单 2 中,我们看到并没有显著减少代码量,但降低了它的复杂性。这样做有两个重要原因:

    1. 不同于 forrange 不会强迫我们初始化某个可变变量。
    2. 迭代会自动执行,所以我们不需要像循环索引一样定义增量。

    在语义上,最初的 for 循环中的变量 i 是一个可变变量。理解 range 和类似方法的价值对理解该设计的结果很有帮助。

    可变变量与参数

    for 循环中定义的变量 i 是单个变量,它会在每次对循环执行迭代时发生改变。range 示例中的变量 i 是拉姆达表达式的参数,所以它在每次迭代中都是一个全新的变量。这是一个细微区别,但决定了两种方法的不同。以下示例有助于阐明这一点。

    清单 3 中的 for 循环想在一个内部类中使用索引变量:

    清单 3. 在内部类中使用索引变量
    ExecutorService executorService = Executors.newFixedThreadPool(10);
     
           for(int i = 0; i < 5; i++) {
             int temp = i;
     
             executorService.submit(new Runnable() {
               public void run() {
                 //If uncommented the next line will result in an error
                 //System.out.println("Running task " + i);
                 //local variables referenced from an inner class must be final or effectively final
     
                 System.out.println("Running task " + temp);
               }
             });
           }
     
           executorService.shutdown();

    我们有一个匿名的内部类实现了 Runnable 接口。我们想在 run 方法中访问索引变量 i,但编译器不允许这么做。

    作为此限制的解决办法,我们可以创建一个局部临时变量,比如 temp,它是索引变量的一个副本。每次新的迭代都会创建变量 temp。在 Java 8 以前,我们需要将该变量标记为 final。从 Java 8 开始,可以将它视为实际的最终结果,因为我们不会再更改它。无论如何,由于事实上索引变量是一个在迭代中改变的变量,for 循环中就会出现这个额外变量。

    现在尝试使用 range 函数解决同一个问题。

    清单 4. 在内部类中使用拉姆达参数
    ExecutorService executorService = Executors.newFixedThreadPool(10);
                           
          IntStream.range(0, 5)
            .forEach(i ->
              executorService.submit(new Runnable() {
                public void run() {
                  System.out.println("Running task " + i);
                }
              }));
     
          executorService.shutdown();

    在作为一个参数被拉姆达表达式接受后,索引变量 i 的语义与循环索引变量有所不同。与清单 3 中手动创建的 temp 非常相似,这个 i 参数在每次迭代中都表现为一个全新的变量。它是实际最终变量,因为我们不会在任何地方更改它的值。因此,我们可以直接在内部类的上下文中使用它 — 且不会有任何麻烦。

    因为 Runnable 是一个函数接口,所以我们可以轻松地将匿名的内部类替换为拉姆达表达式,比如:

    清单 5. 将内部类替换为拉姆达表达式
    IntStream.range(0, 5)
            .forEach(i ->
              executorService.submit(() -> System.out.println("Running task " + i)));

    显然,对于相对简单的迭代,使用 range 代替 for 具有一定优势,但 for 的特殊价值体现在于它能处理更复杂的迭代场景。让我们看看 range 和其他 Java 8 方法孰优孰劣。

    封闭范围

    创建 for 循环时,可以将索引变量封闭在一个范围内,比如:

    清单 6. 一个具有封闭范围的 for 循环
    for(int i = 0; i <= 5; i++) {

    索引变量 i 接受值 01、……5。无需使用 for,我们可以使用 rangeClosed 方法。在本例中,我们告诉 IntStream 将最后一个值限制在该范围内:

    清单 7. rangeClosed 方法
    IntStream.rangeClosed(0, 5)

    迭代此范围时,我们会获得包含边界值 5 在内的值。

    跳过值

    对于基本循环,range 和 rangeClosed 方法是 for 的更简单、更优雅的替代方法,但是如果想跳过一些值该怎么办?在这种情况下,for 对前期工作的需求使该运算变得非常容易。在清单 8 中,for 循环在迭代期间快速跳过两个值:

    清单 8. 使用 for 跳过值
    int total = 0;
    for(int i = 1; i <= 100; i = i + 3) {
       total += i;
    }

    清单 8 中的循环在 1 到 100 内对每次读到的第三个值作求和计算 — 这种复杂运算可使用 for 轻松完成。能否也使用 range 解决此问题?

    首先,可以考虑使用 IntStream 的 range 方法,再结合使用 filter 或 map。但是,所涉及的工作比使用 for 循环要多。一种更可行的解决方案是结合使用 iterate 和 limit

    清单 9. 使用 limit 的迭代
    IntStream.iterate(1, e -> e + 3)
       .limit(34)
       .sum()

    iterate 方法很容易使用;它只需获取一个初始值即可开始迭代。作为第二参数传入的拉姆达表达式决定了迭代中的下一个值。这类似于清单 8,我们将一个表达式传递给 for 循环来递增索引变量的值。但是,在本例中有一个陷阱。不同于 range和 rangeClosed,没有参数来告诉 iterate 方法何时停止迭代。如果我们没有限制该值,迭代会一直进行下去。

    如何解决这个问题?

    我们对 1 到 100 之间的值感兴趣,而且想从 1 开始跳过两个值。稍加运算,即可确定给定范围中有 34 个符合要求的值。所以我们将该数字传递给 limit 方法。

    此代码很有效,但过程太复杂:提前执行数学运算不那么有趣,而且它限制了我们的代码。如果我们决定跳过 3 个值而不是 2 个值,该怎么办?我们不仅需要更改代码,结果也很容易出错。我们需要有一个更好的方法。

    takeWhile 方法

    Java 9 中即将引入的 takeWhile 是一个新方法,它使得执行有限制的迭代变得更容易。使用 takeWhile,可以直接表明只要满足想要的条件,迭代就应该继续执行。以下是使用 takeWhile 实现清单 9 中的迭代的代码。

    清单 10. 有条件的迭代
    IntStream.iterate(1, e -> e + 3)
          .takeWhile(i -> i <= 100) //available in Java 9
          .sum()

    无需将迭代限制到预先计算的次数,我们使用提供给 takeWhile 的条件,动态确定何时终止迭代。与尝试预先计算迭代次数相比,这种方法简单得多,而且更不容易出错。

    与 takeWhile 方法相反的是 dropWhile,它跳过满足给定条件前的值,这两个方法都是 JDK 中非常需要的补充方法。takeWhile 方法类似于 break,而 dropWhile 则类似于 continue。从 Java 9 开始,它们将可用于任何类型的 Stream

    逆向迭代

    与正向迭代相比,逆向迭代同样非常简单,无论使用传统的 for 循环还是 IntStream

    以下是一个逆向的 for 循环迭代:

    清单 11. 使用 for 的逆向迭代
    for(int i = 7; i > 0; i--) {

    range 或 rangeClosed 中的第一个参数不能大于第二个参数,所以我们无法使用这两种方法来执行逆向迭代。但可以使用 iterate 方法:

    清单 12. 使用 iterate 的逆向迭代
    IntStream.iterate(7, e -> e - 1)
          .limit(7)

    将一个拉姆达表达式作为参数传递给 iterate 方法,该方法对给定值进行递减,以便沿相反方向执行迭代。我们使用 limit函数指定我们希望在逆向迭代期间看到总共多少个值。如有必要,还可以使用 takeWhile 和 dropWhile 方法来动态调整迭代流。

    结束语

    尽管传统 for 循环非常强大,但它有些过于复杂。Java 8 和 Java 9 中的新方法可帮助简化迭代,甚至是简化复杂的迭代。方法 rangeiterate 和 limit 的可变部分较少,这有助于提高代码效率。这些方法还满足了 Java 的一个长期以来的要求,那就是局部变量必须声明为 final,然后才能从内部类访问它。将一个可变索引变量更换为实际的 final 参数只有很小的语义差别,但它减少了大量垃圾变量。最终您会得到更简单、更优雅的代码。

    展开全文
  • // List<Integer> 转 Set<String> List<Integer> intList = Arrays.asList(1,2,3,4,5); Set<String> strList = intList.stream() ... strList.stream().forEach(System.out::println);...
  • java8流式编程(一)

    2019-09-30 16:12:01
    传送门 《JAVA8开发指南》为什么你需要关注 JAVA8Java8开发指南》翻译邀请 Java8初体验(一)lambda表达式...Java FP: Java中函数式编程的谓词函数(Predicates)第一部分 话说模式匹配(8) 一个抽取器的例...
  • 1.场景需求 有一个list<Object>,需要将每个对象的一个属性(key)对应的值(value)使用一个符号(*@#¥%_-)拼接起来,那么就可以使用这种方式 代码: ...import java.util.*;...import java.util....
  • dayDcSupplys = dayDcSupplys.stream() .sorted(Comparator.comparing(DfcLv2TotalSupplyPO::getQty, Comparator.nullsLast(Long::compareTo)) .reversed().thenComparing(DfcLv2TotalSupplyPO::...
  • JAVA8流式编程【2】——函数式编程

    千次阅读 2018-05-08 20:05:52
    Java 8 中,我们获得了一组强大的新的函数特性和语法。函数式编程已有数十年的历史,而且与面向对象的编程相比,函数式编程通常更简洁、更具表达力、更不容易出错,而且更容易并行化。所以在 Java 程序中引入函数...
  • java8流式编程实战

    2021-09-10 10:41:32
    // TODO: 2021/8/31 流式编程与普通编程对比 class ImperativeRandoms { // TODO: 2021/8/31 外部迭代 public static void main(String[] args) { Random rand = new Random(47); SortedSet<Integer> ...
  • Java 8 中引入了新特性,流式编程思想,为其增加了有一个新的亮点!因为流的一个核心好处是,使得代码程序更加精简并且更易理解。在某些数情况下,将对象存储在数组、集合中是为了处理他们,而现在你可以把编程的...
  • JAVA8流式编程【5】——方法引用

    千次阅读 2018-05-08 20:12:40
    Lambda 表达式被广泛用在函数式编程中,但它们很难阅读和理解。在许多情况下,lambda 表达式的存在只是为了传递一个或多个形参,最好将它替换为方法引用。在本文中,您将学习如何识别代码中的传递 lambda 表达式,...
  • JAVA8流式编程【1】——函数纯度

    千次阅读 2018-05-08 20:04:22
    函数管道和 Stream API我们使用 Stream 在 Java™ 中构建函数管道。在函数式代码中使用 Stream 有 3 个好处:Stream 简洁、富于表达、非常优雅,而且代码读起来就像是问题陈述。Stream 采用了惰性计算,这使得...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 25,503
精华内容 10,201
关键字:

java8流式编程

java 订阅