java8 Stream流操作集合

Stream 流的简介

一句话简介:从支持数据处理操作生成的元素序列

数据处理操作:类似数据库的操作。
源:数据。
元素序列:流提供了可以访问特定元素有序值的接口。

流的组成

组成:数据源 + 中间操作 + 终端操作

流操作分类

在这里插入图片描述
在这里插入图片描述
有状态操作:需要建立在所有的数据基础上,也就是需要等待前面的流处理完后,再进行统一的操作。
无状态操作:对单个元素进行处理。

短路操作:一个元素满足条件后,后面的就不用执行。
非短路操作:数据集中的每个数据都要执行一遍。

注:终端操作结束后流就不可用了。

流的使用

在开始使用流之前,先做好准备工作:

  1. 创建一个实体类,作为数据的来源
public class Sku {
    private Integer skuId;
    private String skuName;
    private Double skuPrice;
    // 购买个数
    private Integer totalNum;
    private Double totalPrice;
    // 商品类型
    private Enum skuCategory;

    public Sku(Integer skuId, String skuName, Double skuPrice, Integer totalNum, Double totalPrice, Enum skuCategory) {
        this.skuId = skuId;
        this.skuName = skuName;
        this.skuPrice = skuPrice;
        this.totalNum = totalNum;
        this.totalPrice = totalPrice;
        this.skuCategory = skuCategory;
    }

    @Override
    public String toString() {
        return "Sku{" +
                "skuId=" + skuId +
                ", skuName='" + skuName + '\'' +
                ", skuPrice=" + skuPrice +
                ", totalNum=" + totalNum +
                ", totalPrice=" + totalPrice +
                ", skuCategory=" + skuCategory +
                '}';
    }

    public Integer getSkuId() {
        return skuId;
    }

    public void setSkuId(Integer skuId) {
        this.skuId = skuId;
    }

    public String getSkuName() {
        return skuName;
    }

    public void setSkuName(String skuName) {
        this.skuName = skuName;
    }

    public Double getSkuPrice() {
        return skuPrice;
    }

    public void setSkuPrice(Double skuPrice) {
        this.skuPrice = skuPrice;
    }

    public Integer getTotalNum() {
        return totalNum;
    }

    public void setTotalNum(Integer totalNum) {
        this.totalNum = totalNum;
    }

    public Double getTotalPrice() {
        return totalPrice;
    }

    public void setTotalPrice(Double totalPrice) {
        this.totalPrice = totalPrice;
    }

    public Enum getSkuCategory() {
        return skuCategory;
    }

    public void setSkuCategory(Enum skuCategory) {
        this.skuCategory = skuCategory;
    }
}

  1. 定义一个枚举类,里面放商品类型

public enum SkuCategoryEnum {
    CLOTHING(10, "服装类"),
    SELECTRONICE(20, "数码类"),
    SPORTS(30, "运动类"),
    BOOKS(40, "图书类");
    //  商品类型编号
    private Integer code;
    // 商品类型名称
    private String name;

    SkuCategoryEnum(Integer code, String name) {
        this.code = code;
        this.name = name;
    }
}

  1. 定义一个Service 类
public class CartService {
    // 所有添加到购物车的商品
    private static List<Sku> cartSkuList = new ArrayList<Sku>() {
        {
            add(new Sku(654032, "大疆无人机", 4999.00, 1,
                    4999.00, SkuCategoryEnum.SELECTRONICE));

            add(new Sku(467325, "VR-体机", 8999.00, 1,
                    8999.00, SkuCategoryEnum.SELECTRONICE));

            add(new Sku(967325, "索尼相机", 12000.00, 2,
                    24000.00, SkuCategoryEnum.SELECTRONICE));

            add(new Sku(856325, "Java并发编程", 50.00, 3,
                    150.00, SkuCategoryEnum.BOOKS));

            add(new Sku(654325, "Oracle入门", 45.00, 2,
                    90.00, SkuCategoryEnum.BOOKS));

            add(new Sku(145674, "耐克T恤", 100.00, 4,
                    400.00, SkuCategoryEnum.CLOTHING));

            add(new Sku(142564, "阿迪达斯T恤", 120.00, 2,
                    400.00, SkuCategoryEnum.CLOTHING));

            add(new Sku(356325, "篮球", 350.00, 2,
                    700.00, SkuCategoryEnum.SPORTS));

            add(new Sku(568410, "羽毛球", 1500.00, 2,
                    3000.00, SkuCategoryEnum.SPORTS));

        }
    };

    // 获取商品信息列表
    public static List<Sku> getCartSkuList() {
        return cartSkuList;
    }
}
  1. 定义流操作类

public class StreamOperator {

    List<Sku> list;

    @Before
    public void init() {
        list = CartService.getCartSkuList();
    }


    @Test
    public void filterTest() {
        list.stream()
                // 不是图书类的过滤掉
                .filter(sku -> sku.getSkuCategory().equals(SkuCategoryEnum.BOOKS))
                // 打印中间操作的结果集
                .forEach(item -> System.out.println(JSON.toJSONString(item, true)));
    }

    // map:将一个元素转换成另一个类型的元素
    @Test
    public void mapTest() {
        list.stream()
                // 将 Sku 类型的集合转换成 String 类型的集合
                .map(sku -> sku.getSkuName())
                // 打印中间操作的结果集
                .forEach(item -> System.out.println(JSON.toJSONString(item, true)));

    }

    // 扁平化map 将对象转换成流
    @Test
    public void flatMapTest() {
        list.stream()
                // 接收一个元素,返回一个新的流,并且与其他元素产生的流合并,同一交给终端操作
                .flatMap(sku -> Arrays.stream(sku.getSkuName().split("")))
                .forEach(item -> System.out.println(JSON.toJSONString(item, true)));
    }


    /**
     * peek使用:对流中元素进行遍历操作,与forEach类似,但不会销毁流元素
     */
    @Test
    public void peek() {
        list.stream()

                // peek 与 forEach 交替执行,因为后面的forEach是无状态的
                .peek(sku -> System.out.println(sku.getSkuName()))

                .forEach(item -> System.out.println( JSON.toJSONString(item, true)));
    }

    /**
     * sort使用:对流中元素进行排序,可选则自然排序或指定排序规则。有状态操作
     */
    @Test
    public void sortTest() {
        list.stream()
                // 此时的 peek 不会和后面的 forEach交替操作,因为后面的sorted是有状态的
                .peek(sku -> System.out.println(sku.getSkuName()))

                //sort
                .sorted(Comparator.comparing(Sku::getTotalPrice))

                .forEach(item ->  System.out.println( JSON.toJSONString( item, true)));
    }

    /**
     * distinct使用:对流元素进行去重。有状态操作
     */
    @Test
    public void distinctTest() {
        list.stream()
                .map(sku -> sku.getSkuCategory())

                // distinct
                .distinct()

                .forEach(item -> System.out.println( JSON.toJSONString(  item, true)));


    }

    /**
     * skip使用:跳过前N条记录。有状态操作
     */
    @Test
    public void skipTest() {
        list.stream()

                .sorted(Comparator.comparing(Sku::getTotalPrice))

                // 过滤掉前 3 条数据
                .skip(3)

                .forEach(item ->  System.out.println(  JSON.toJSONString( item, true)));
    }

    /**
     * limit使用:截断前N条记录。有状态操作
     */
    @Test
    public void limitTest() {
        list.stream()
                .sorted(Comparator.comparing(Sku::getTotalPrice))
                // 跳过前两页的数据
                .skip(2 * 3)

                // limit
                .limit(3)

                .forEach(item -> System.out.println( JSON.toJSONString( item, true)));
    }

    /**
     * allMatch使用:终端操作,短路操作。所有元素都匹配,则返回true,否则返回false
     */
    @Test
    public void allMatchTest() {
        boolean match = list.stream()

                .peek(sku -> System.out.println(sku.getSkuName()))

                // allMatch
                .allMatch(sku -> sku.getTotalPrice() > 100);

        System.out.println(match);
    }

    /**
     * anyMatch使用:任一元素匹配,返回true
     */
    @Test
    public void anyMatchTest() {
        boolean match = list.stream()

                .peek(sku -> System.out.println(sku.getSkuName()))

                // anyMatch
                .anyMatch(sku -> sku.getTotalPrice() > 100);

        System.out.println(match);
    }

    /**
     * noneMatch使用:任何元素都不匹配,返回true
     */
    @Test
    public void noneMatchTest() {
        boolean match = list.stream()

                .peek(sku -> System.out.println(sku.getSkuName()))

                // noneMatch
                .noneMatch(sku -> sku.getTotalPrice() > 10_000);

        System.out.println(match);
    }

    /**
     * 找到第一个元素
     */
    @Test
    public void findFirstTest() {
        Optional<Sku> optional = list.stream()

                .peek(sku -> System.out.println(sku.getSkuName()))

                // findFirst
                .findFirst();

        System.out.println(
                JSON.toJSONString(optional.get(), true));
    }

    /**
     * 找任意一个
     * 若是串行操作,findAny 和 findFirst 没有区别,返回的值是一样的,
     * 若是并行操作,findAny 可能随机返回一个值,在并行上面比 findFirst快
     */
    @Test
    public void findAnyTest() {
        Optional<Sku> optional = list.stream()

                .peek(sku -> System.out.println(sku.getSkuName()))

                // findAny
                .findAny();

        System.out.println(
                JSON.toJSONString(optional.get(), true));
    }

    /**
     * max使用:
     */
    @Test
    public void maxTest() {
        OptionalDouble optionalDouble = list.stream()
                // 获取总价  将一个元素映射成 Double 类型的元素
                .mapToDouble(Sku::getTotalPrice)
                .max();

        System.out.println(optionalDouble.getAsDouble());
    }

    /**
     * min使用
     */
    @Test
    public void minTest() {
        OptionalDouble optionalDouble = list.stream()
                // 获取总价
                .mapToDouble(Sku::getTotalPrice)

                .min();

        System.out.println(optionalDouble.getAsDouble());
    }

    /**
     * count使用
     */
    @Test
    public void countTest() {
        long count = list.stream()
                .count();

        System.out.println(count);
    }
}

流的构建

流有4种构建方式:由值、数组、文件、函数创建流。

1.创建 StreamConstructor 类


public class StreamConstructor {


    /**
     * 由数值直接构建流
     */
    @Test
    public void streamFromValue() {
        Stream stream = Stream.of(1, 2, 3, 4, 5);

        stream.forEach(System.out::println);
    }

    /**
     * 通过数组构建流
     */
    @Test
    public void streamFromArray() {
        int[] numbers = {1, 2, 3, 4, 5};

        IntStream stream = Arrays.stream(numbers);
        stream.forEach(System.out::println);
    }

    /**
     * 通过文件生成流
     *
     * @throws IOException
     */
    @Test
    public void streamFromFile() throws IOException {
        // TODO 此处替换为本地文件的地址全路径
        String filePath = "...\\CartService.java";

        Stream<String> stream = Files.lines(
                Paths.get(filePath));

        stream.forEach(System.out::println);
    }

    /**
     * 通过函数生成流(无限流)
     */
    @Test
    public void streamFromFunction() {
        // 偶数流,无限生成,流之间迭代生成
//        Stream stream = Stream.iterate(0, n -> n + 2);

        // 随机数,无限随机生成,后一个流不会基于上一个流生成
        Stream stream = Stream.generate(Math::random);

        stream.limit(100)
                .forEach(System.out::println);

    }

}

收集器

作用:将流中的元素累积成一个结果,作用于终端操作collect()。

collect:是一个终端操作,是流收集的最后一个步骤,是一个方法,接收Collector接口实现类。
Collector:是一个接口。
Collectors:是一个工具类,里面定义了一些收集器。

预定义收集器功能

  1. 将流元素归约和汇总成一个值。
  2. 将流元素分组。
  3. 将流元素分区。

代码演示:


public class StreamCollector {


    /**
     * 集合收集器
     */
    @Test
    public void toList() {

        List<Sku> list = CartService.getCartSkuList();

        List<Sku> result = list.stream()
                .filter(sku -> sku.getTotalPrice() > 100)

                // 将集合中的元素收集成 list 返回
                .collect(Collectors.toList());

        System.out.println(
                JSON.toJSONString(result, true));

    }

    /**
     * 分组 根据商品类别进行分组
     */
    @Test
    public void group() {
        List<Sku> list = CartService.getCartSkuList();

        // Map<分组条件,结果集合>
        Map<Object, List<Sku>> group = list.stream()
                // 将结果按类别进行分组
                .collect(Collectors.groupingBy(sku -> sku.getSkuCategory()));

        System.out.println(
                JSON.toJSONString(group, true));
    }

    /**
     * 分区,分组的特殊形式,将数据根据boolean值分为两组,分别是true和false
     */
    @Test
    public void partition() {
        List<Sku> list = CartService.getCartSkuList();

        Map<Boolean, List<Sku>> partition = list.stream()
                .collect(Collectors.partitioningBy(
                        sku -> sku.getTotalPrice() > 100));

        System.out.println(
                JSON.toJSONString(partition, true));
    }
}

归约与汇总

待补充…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值