Java8中的Stream

使用java8新增的Stream操作集合

java8还新增了Stream、IntStream、LongStream等流式API,这些API代表多个支持串行和并行聚集操作的元素。其中Stream是一个通用的流接口,而其他的则对应int、long的流。
java8还为上面流式API提供了对用的Builder,用来通过这些Builder来创建对应的流。
独立使用Stream的步骤:

  • 使用Stream或XxxStream的builder()类方法创建该Stream对应的Builder;
  • 重复调用Builder的add方法向该流中添加多个元素。
  • 调用Builder的build方法获取对应的Stream。
  • 调用Stream的聚集方法。
        IntStream is=IntStream.builder()
                .add(10)
                .add(-32)
                .add(54)
                .add(-23)
                .build();
        //下面聚集方法的代码每次只能执行一次
        System.out.println("is所有元素中最大值:"+is.max().getAsInt());
        System.out.println("is所有元素中最小值:"+is.min().getAsInt());
        System.out.println("is所有元素的总数:"+is.count());
        System.out.println("is所有元素的平均值:"+is.average());
        System.out.println("is所有元素的平方值是否都大于20:"
        +is.allMatch(ele->ele*ele>20));
        System.out.println("is任何元素的平方值是否都大于20:"
        +is.anyMatch(ele->ele*ele>20));

上面执行方法的代码每次只能执行一行,因此需要把其他行注释掉。

Stream提供了大量的方法进行聚集操作,这些方法既可以是“中间的”也可以是“末端的”。

中间方法:
中间操作允许保持打开状态,并允许直接调用后续方法;
末端方法:
末端方法是对流的最终操作,当对某个Stream执行末端方法后,该流将会被消耗切不可再用。
除此之外,关于流的方法还有如下特征:
有状态的方法:
这种方法会给流增加一些新特性,比如元素的唯一性,元素的最大数量、保证元素以排序的方法被处理等。有状态的方法往往需要更大的性能开销。
短路方法:
短路方法可以尽早结束对流的操作,不必检查所有元素。

中间方法的简单介绍

  • filter(Predicate predicate):过滤Stream中所有不符合Predicate的元素。
  • map(Function function):映射元素,lambda把原有的元素转换为另一个元素, 不会改变个数;
  • flatMap():扁平化映射,比如将二维数组映射为一维数组;
  • mapToXxx(ToXxxFunction mapper):使用ToXxxFunction对流中的元素执行一对一的转换,该方法返回的新流中包含了ToXxxFunction转换生成的所有元素。
  • peek(Consumer action):依次对每个元素执行一些操作,该方法返回的流与原流包含相同的元素。
  • distinct():该方法用于排序流中所有重复的元素。这是一个有状态的方法。
  • sorted():该方法用于保证流中的元素在后续的访问中处于有序状态,这是一个有状态的方法。
  • limit(long maxSize):该方法用于保证对该流的后续访问中最大允许访问的元素的个数。这是一个有状态的、短路的方法。

末端方法介绍

  • forEach(Consumer action):遍历流中的所有元素,对每个元素执行action;
  • toArray():将流中所有元素转换成一个数组;
  • reduce():该方法有三个重载版本,都用于通过某种操作来合并流中的元素。
  • min()、max():分别返回流中的最小值和最大值;
  • count():返回流中所有元素的数量;
  • anyMatch(Predicate predicate):判断流中是否至少包含一个元素满足Predicate条件;
  • AllMatch(Predicate predicate):判断流中是否所有元素满足Predicate条件;
  • noneMatch(Predicate predicate):判断流中是否所有元素都不符合Predicate条件;
  • findFirst():返回流中的第一个元素。
  • findAny():返回流中的任意一个元素。

除此之外java8允许使用流式API来操作集合,Collection接口提供了一个stream默认方法,该方法可返回该集合对应流,接下来即可通过流式API来操作集合了。

        Collection collection= new ArrayList();

        collection.add("Java");
        collection.add("Python");
        collection.add("C++");
        collection.add("go语言");

        //统计元素中包含字符o的元素个数
        System.out.println(collection.stream().filter(ele->((String)ele).contains("o")).count());
        //统计元素字符串大于3的元素个数
        System.out.println(collection.stream().filter(ele->((String)ele).length()>3).count());
        //先调用Collection对象的Stream方法将集合转换为Stream对象
        //再调用Stream的mapToint方法获取原有Stream对应的IntStream
        collection.stream().mapToInt(ele->((String)ele).length())
        .forEach(System.out::println);

java中的常用接口

  • Predicate:断言接口
    对应Lambda 需要一个参数,返回结果是boolean值;
    (a)->{return true|false}

  • Function:函数接口
    对应Lambda 需要一个参数,返回一个结果,参数和结果类型可以不一致;

  • BiPredicate 双参数断言
    对应Lambda 需要两个参数,返回结果是boolean值
    (a,b)->{return ture|false}

  • BiFunction:双参数函数接口
    对应Lambda 需要两个参数,返回一个结果
    (a,b)->{ return }

  • Consumer:消费者接口
    一个参数,不返回结果

  • Biconsumer:双参数消费者接口
    两个参数,不返回结果

  • Supplier:生产者接口
    没有参数,返回一个结果
    ()->{ return 结果}

Stream和接口的应用

  • 分组
    定义一个学生类,成员变量姓名、性别、城市,实例化多个学生类,按性别或城市分类,放在map集合中。
package demo1;

import com.sun.xml.internal.ws.api.ha.StickyFeature;

public class Student {
    private String name;
    private String sex;
    private String city;

    public Student(String name, String sex, String city) {
        this.name = name;
        this.sex = sex;
        this.city = city;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", city='" + city + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public String getSex() {
        return sex;
    }

    public String getCity() {
        return city;
    }
}
package demo1;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Test {
    public static void main(String[] args) {
        List<Student> studentsList = Arrays.asList(
                new Student("张三", "男", "西安"),
                new Student("李四", "女", "北京"),
                new Student("王五", "男", "南京"),
                new Student("赵六", "男", "西安"),
                new Student("周七", "女", "上海")
        );

        Stream<Student> stream = studentsList.stream();
        Map<String, List<Student>> collect = stream.collect(Collectors.groupingBy((student) -> {
            return student.getSex();
        }));
        System.out.println(collect);

//{女=[Student{name='李四', sex='女', city='北京'}, Student{name='周七', sex='女', city='上海'}],
 男=[Student{name='张三', sex='男', city='西安'}, Student{name='王五', sex='男', city='南京'}, 
 Student{name='赵六', sex='男', city='西安'}]}//

    }
}

下面是groupingBy方法的源代码,可以看到它需要传入一个函数式接口,所以传入student并返回student.getSex作为返回值。

Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
                                          Collector<? super T, A, D> downstream) {
        return groupingBy(classifier, HashMap::new, downstream);
    }
  • 扁平化映射
package demo1;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import static java.util.Arrays.stream;

public class FlatmapTest {
    public static void main(String[] args) {
        //创建二维数组
        ArrayList<String[]> lists = new ArrayList<>();
                lists.add(new String[]{"张三","李四"});
                lists.add(new String[]{"黎明","张学友"});
                lists.add(new String[]{"刘德华","郭富城"});


        //扁平化映射
        System.out.println(lists.stream().flatMap(strings -> stream(strings)).collect(Collectors.toList()));
    }
}

Stream的重要思想
Pipeline流水线思想:把流中的数据一个接着一个进行处理,每个数据会经过filter、map这种中间方法依次调用,但是这些不会立即生效,直到使用像forEach这种末端方法时,才会将数据一个个的取出来按调用方法的顺序执行。而且运算过程中不会改变原始集合,收集器会生成新的集合对象。

流的生成

  • 用集合生成:List.stream
  • 根据数字:IntStream.of(1,2,3,4)
  • 把数组变成流:Arrays.stream(数组)
  • 把文件中的每行读取出来作为流元素:Files.lines(Paths.get(文件名)).forEach(s->System.out.println(s));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值