当前位置:   article > 正文

lambda_函数式编程_stream流

lambda_函数式编程_stream流

一. lambda表达式

jdk 1.8 引入了 lambda表达式,能够帮助我们,编写代码时更加简洁,也为函数式编程提供了支持

lambda表达式作用:简化匿名实现类的书写,实现接口抽象方法;

语法结构

(参数类型 参数名1,参数类型 参数名2,……参数类型 参数名n)->{
    //方法体
}

1)()中的内容就是方法中的参数列表,包括参数类型、参数名,其中的参数类型可以忽略,当参数个数只有一个时也可以忽略掉小括号;
2){}中的内容是方法中的方法体,当方法体中只有一行代码时可忽略掉{},当方法体中只有一行代码并且需要返回值时也可以忽略掉return// jdk 1.8 之前
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello World!");
    }
});

// jdk 1.8
new Thread(()-> System.out.println("hellowod 2"));
List<Integer> names = Arrays.asList(1, 10, 3, 2,1);
        //==============  // jdk 1.8 之前===========创建一个匿名的比较器对象
        Collections.sort(names, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println("o1:"+o1+"<>o2:"+o2+"=="+o1.compareTo(o2));
                return o1.compareTo(o2);
            }
        });
        //============// jdk 1.8 使用Lambda============
        Collections.sort(names,(Integer o1,Integer o2)->{
                        System.out.println("o1:"+o1+"<>o2:"+o2+"=="+o1.compareTo(o2));
                        return o1.compareTo(o2);
                      } );
        System.err.println(names);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

二. forEach 循环

jdk 1.8 之前
List<Integer> names = Arrays.asList(1, 10, 3, 2,1);

//no.1
for(Integer number : numbers){
    System.out.println(number);
}

//no.2
for(int index=0,len=numbers.size();index<len;index++){
    System.out.println(numbers.get(index));
}
使用jdk1.8后,可这么写
//no.1
numbers.forEach((Integer integer) -> {
    System.out.println(integer);
});

//no.2
numbers.forEach(integer -> {
    System.out.println(integer);
});

//no.3
numbers.forEach(integer -> System.out.println(integer));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

三. 函数式 编程 " :: "

“::” 表示 内存中的某个方法

如果一个箭头函数中的引用仅仅是使用 函数帮我们处理我们的参数,我们可以把某个函数当做参数传递

 numbers.forEach(integer -> System.out.println(integer));
 上述写法我们仅仅使用了 函数  "System.out.println" 的特性帮我们处理数据,我们可以把这个函数当做参数传递
 
 numbers.forEach(System.out::println);
  • 1
  • 2
  • 3
  • 4

四. Stream 流

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

±-------------------+ ±-----+ ±-----+ ±–+ ±------+ | stream of elements ±----> |filter±> |sorted±> |map±> |collect| ±-------------------+ ±-----+ ±-----+ ±–+ ±------+

以上的流程转换为 Java 代码为:

List<Integer> transactionsIds = 
widgets.stream()
             .filter(b -> b.getColor() == RED)
             .sorted((x,y) -> x.getWeight() - y.getWeight())
             .mapToInt(Widget::getWeight)
             .sum();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4.1 什么是 Stream?

Stream(流)是一个来自数据源的元素队列并支持聚合操作

  • 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
  • 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
  • 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。

和以前的Collection操作不同, Stream操作还有两个基础的特征:

  • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
  • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

首先对stream的操作可以分为两类,中间操作(intermediate operations)和结束操作(terminal operations): 中间操作总是会惰式执行,调用中间操作只会生成一个标记了该操作的新stream。 结束操作会触发实际计算,计算发生时会把所有中间操作积攒的操作以pipeline的方式执行,这样可以减少迭代次数。计算完成之后stream就会失效。 虽然大部分情况下stream是容器调用Collection.stream()方法得到的,但stream和collections有以下不同: 无存储。stream不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,Java容器或I/O channel等。 为函数式编程而生。对stream的任何修改都不会修改背后的数据源,比如对stream执行过滤操作并不会删除被过滤的元素,而是会产生一个不包含被过滤元素的新stream。 惰式执行。stream上的操作并不会立即执行,只有等到用户真正需要结果的时候才会执行。 可消费性。stream只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。

4.2 生成流

stream() − 为集合创建串行流。

List strings = Arrays.asList(“abc”, “”, “bc”, “efg”, “abcd”,“”, “jkl”); List filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

4.3 使用

forEach

Stream 提供了新的方法 ‘forEach’ 来迭代流中的每个数据。

List<Integer> ids = Arrays.asList(1, 10, 3, 2,1);
ids.stream().forEach(System.out::println);
  • 1
  • 2
map (用于替换元素)

map 方法用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 获取对应的平方数
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
  • 1
  • 2
  • 3
filter (用于淘汰元素)

filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤出空字符串:

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
long count = strings.stream().filter(string -> string.isEmpty()).count();
  • 1
  • 2
  • 3
limit (用于分页)

limit 方法用于获取指定数量的流。 以下代码片段使用 limit 方法打印出 10 条数据:

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
  • 1
  • 2
sorted (用于排序)

sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序:

Random random = new Random();
random.ints(0,10).limit(10).sorted().forEach(System.out::println);
  • 1
  • 2
reduce (用户聚合,将多个合成一个)
 @Test
    public void test05(){
        List<Integer> names = Arrays.asList(1, 10, 3, 2,1);

        // 求和
        int value = names.stream().reduce((x,y)->x+y).get();
        System.out.println(value);

        // 函数式编程
        int value2 = names.stream().reduce(Integer::sum).get();
        System.out.println(value2);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
collect()

用于将流中的数据 转移到一个新的集合 参数必须使用 Collectors. 对象创建

Collectors 类实现了很多对数据处理的操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:

List<Integer> ids = Arrays.asList(1, 10, 3, 2,1);
// 将流中的数据转成 list
ids.stream().collect(Collectors.toList());
// 将流中的数据转成 set
ids.stream().collect(Collectors.toSet());
// 将流中的数据转成 map
ids.stream().collect(Collectors.toMap(i->i, integer -> integer*integer));
// 将流中的数据 聚合统计 放入map
Map<Integer, Long> collect = ids.stream().collect(Collectors.groupingBy(i -> i,
                                                                       Collectors.counting()));

// 将流中的数据  替换成字符串形式,然后 拼接返回
 String collect1 = ids.stream().map(id -> id.toString()).collect(Collectors.joining(","));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

五. stream流时机使用案例

  • List<Obj> 转为 List<Long>
List<Long> courseIds = records.stream().map(lesson -> lesson.getCourseId()).collect(Collectors.toList());
  • 1
  • List<Obj> 转为 Map<Long,Obj>
Map<Long, CourseSimpleInfoDTO> courseMap = courseList.stream().collect(Collectors.toMap(c -> c.getId(), c -> c));
  • 1
  • List<Obj> 转为 Map<Long,Integer>
Map<Long, Integer> map = list.stream().collect(Collectors.toMap(IdAndNumDTO::getId, IdAndNumDTO::getNum));
  • 1
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/782578
推荐阅读
相关标签
  

闽ICP备14008679号