Java8新特性——Stream流

一、Stream流简介

1.1 什么是Stream流?

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

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

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

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

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

———摘自菜鸟教程
在这里插入图片描述

流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
集合讲的是数据,流讲的是计算!

1.2 为什么使用Stream流?

Stream流可以对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。Stream API 借助于同样新出现的Lambda表达式,极大的提高编程效率和程序可读性

1.3 Stream流的特性

  • Stream 自己不会存储元素。
  • Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
  • Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

二、创建Stream流

一个数据源(如:集合、数组),获取一个流。

2.1 通过 Collection 扩展接口创建流

Collection 接口被扩展,提供了两个获取流的方法。

default Stream<E> stream() : 返回一个顺序流
default Stream<E> parallelStream() : 返回一个并行流

/**
 * Collection 扩展接口
 * 通过 Collection 的 Stream()方法或 parallelStream()方法创建 Stream
 */
System.out.println("======Collection======");
List<String> list = Arrays.asList("1", "2", "3", "zs", "abc");
Stream<String> stream1 = list.stream();
Stream<String> stream2 = list.parallelStream();

小贴士:
并行流就是把一个内容分成多个数据块,并用不同的线程分别处理没歌数据块的流。
Java 8中将并行进行了优化,我们可以很容易的对数据进行并行操作。Stream API 可以声明性地通过 parallel() 与 sequential() 在并行流与顺序流之间进行切换。

2.2 由数组创建流

Arrays 的静态方法 stream() 可以获取数组流。

static <T> Stream<T> stream(T[] array): 返回一个流

/**
 * 由数组创建流
 * 通过 Arrays中的静态方法 stream() 获取数组流
 */
System.out.println("======Arrays======");
IntStream intStream = Arrays.stream(new int[]{1, 2, 3});
LongStream longStream = Arrays.stream(new long[]{123L, 46L});
DoubleStream doubleStream = Arrays.stream(new double[]{12.3, 34.56});

Integer[] integerNums = new Integer[10];
Long[] longNums = new Long[10];
Double[] doubleNums = new Double[10];
Stream<Integer> integerStream2 = Arrays.stream(integerNums);
Stream<Long> longStream2 = Arrays.stream(longNums);

2.3 由值创建流

可以使用静态方法 Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数。

public static<T> Stream<T> of(T... values) : 返回一个流

/**
 * 由值创建流
 * 通过 Stream()类中的 of()静态方法获取流
 */
System.out.println("======of()======");
Stream<String> streamValue = Stream.of("a", "b", "c");

2.4 由函数创建流

可以使用静态方法 Stream.iterate() 和Stream.generate(), 创建无限流。

迭代 public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
生成 public static<T> Stream<T> generate(Supplier<T> s)

System.out.println("======function()======");
//迭代(需要传入一个种子,也就是起始值,然后传入一个一元操作)
Stream<Integer> integerStream3 = Stream.iterate(0, x -> x + 2).limit(10);
integerStream3.forEach(System.out::println);
//生成(无限产生对象)
Stream<Double> doubleStream3 = Stream.generate(() -> Math.random());
doubleStream3.forEach(System.out::println);

三、Stream流的中间操作

一个中间操作链,对数据源的数据进行处理。

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。

/**
 * 中间操作
 */
List<UserEntity> userList = new ArrayList<>();
userList.add(new UserEntity("zhangsan", 20));
userList.add(new UserEntity("lisi", 28));
userList.add(new UserEntity("wangwu", 35));
userList.add(new UserEntity("xiaoming", 16));
userList.add(new UserEntity("Amay", 36));
userList.add(new UserEntity("Jack", 45));

3.1 筛选与切片

方法描述
filter(Predicate p)接收 Lambda , 从流中排除某些元素。
distinct()筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
limit(long maxSize)截断流,使其元素不超过给定数量。
skip(long n)跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
/**
 * 筛选与切片
 * filter:接受 Lambda,从流中排出某些元素;
 * limit:截断流,使其元素不超过给定数量;
 * skip(n):跳过元素,返回一个扔掉了前 n 个元素的流。如果流中元素不足 n个,就返回一个空流。(与 limit(n) 互补)
 * distinct:筛选,通过流所生成元素的 hashCode()和equals()去除重复元素。
 */
// 1、filter
System.out.println("======filter======");
// 外部迭代(Java 8之前做的都是外部迭代)
System.out.println("======外部迭代======");
Iterator<UserEntity> iterator = userList.iterator();
while (iterator.hasNext()){
    System.out.println(iterator.next());
}
// 内部迭代:迭代操作在 Stream API 内部完成(对外部迭代进行的优化)
System.out.println("======内部迭代======");
System.out.println("测试中间操作...过滤所有年龄小于25的user对象");
Stream<UserEntity> stream = userList.stream()
        // 所有的中间操作不会做任何处理
        .filter(userEntity -> {
            return userEntity.getAge() <= 25;
        });
// 只有当做终止操作时,所有的中间操作会一次性的全部执行,这称为"惰性求值"
stream.forEach(System.out::println);


// 2、limit
System.out.println("======limit======");
System.out.println("测试中间操作...过滤后限定数量不超过3");
userList.stream().filter(userEntity -> userEntity.getAge() >= 30)
        .limit(3).forEach(System.out::println);


// 3、skip
System.out.println("======skip======");
System.out.println("测试中间操作...过滤后跳过前2个元素");
userList.stream().filter(userEntity -> userEntity.getAge() >= 15)
        .skip(2).forEach(System.out::println);


// 4、distinct
System.out.println("======distinct======");
System.out.println("测试中间操作...通过distinct进行筛选");
userList.stream().distinct().forEach(System.out::println);

3.2 映射

方法描述
map(Function f)接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
mapToDouble(ToDoubleFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。
mapToInt(ToIntFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。
mapToLong(ToLongFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。
flatMap(Function f)接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
/**
 * 映射
 */
List<UserEntity> userList = Arrays.asList(new UserEntity("a",1),new UserEntity("ab",3),new UserEntity("c",11),new SUserEntityu("f",12));
Stream<UserEntity> stream = userList .stream();
// 去除list中所有的年龄
stream.map(UserEntity::getAge).forEach(System.out::println);
// 把所有年龄再返回一个集合
List<Integer> collect = stream.map(UserEntity::getAge).collect(Collectors.toList());
stream.flatMap(userEntity-> test1.filterCharacter(userEntity.getName())).forEach(System.out::println);

3.3 排序

方法描述
sorted()产生一个新流,其中按自然顺序排序
sorted(Comparator comp)产生一个新流,其中按比较器顺序排序
/**
 * stream排序sorted
 */
// 1、匿名内部类的方式
Stream<UserEntity> sortedStream1 = userEntities.stream();
sortedStream1.sorted(new Comparator<UserEntity>() {
    @Override
    public int compare(UserEntity o1, UserEntity o2) {
        // 升序
        return o1.getAge() - o2.getAge();
    }
}).forEach(new Consumer<UserEntity>() {
    @Override
    public void accept(UserEntity userEntity) {
        System.out.println("使用匿名内部类的方式排序:" + userEntity.toString());
    }
});
// 2、lambda的方式
Stream<UserEntity> sortedStream2 = userEntities.stream();
sortedStream2.sorted((o1, o2) -> o1.getAge() - o2.getAge())
        .forEach(userEntity -> System.out.println("使用lambda的方式排序:" + userEntity.toString()));

四、Stream流的终止操作

一个终止操作,执行中间操作链,并产生结果。

/**
 * 终止操作
 */
List<UserEntity> userList = new ArrayList<>();
userList.add(new UserEntity("zhangsan", 20));
userList.add(new UserEntity("lisi", 28));
userList.add(new UserEntity("wangwu", 35));
userList.add(new UserEntity("xiaoming", 16));
userList.add(new UserEntity("Amay", 36));
userList.add(new UserEntity("Jack", 45));

4.1 查找与匹配

方法描述
allMatch(Predicate p)检查是否匹配所有元素
anyMatch(Predicate p)检查是否至少匹配一个元素
noneMatch(Predicate p)检查是否没有匹配所有元素
findFirst()返回第一个元素
findAny()返回当前流中的任意元素
count()返回流中元素总数
max(Comparator c)返回流中最大值
min(Comparator c)返回流中最小值
forEach(Consumer c)内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了)
/**
 * streamMatch匹配--noneMatch
 * noneMatch表示判断条件里的元素,所有的都不是,就返回true
 */
System.out.println("======noneMatch======");
// 1、匿名内部类的方式
Stream<UserEntity> noneMatch1 = userList.stream();
boolean result = noneMatch1.noneMatch(new Predicate<UserEntity>() {
    @Override
    public boolean test(UserEntity userEntity) {
        return userEntity.getAge() > 32;
    }
});
System.out.println("noneMatch使用匿名内部类的方式:" + result);
// 2、lambda的方式
Stream<UserEntity> noneMatch2 = userList.stream();
boolean result2 = noneMatch2.noneMatch((user) -> user.getAge() > 35);
System.out.println("noneMatch使用lambda的方式:" + result2);



/**
 * streamMatch匹配--allMatch
 * allMatch表示判断条件里的元素,所有都是就返回true
 */
System.out.println("======allMatch======");
// 1、匿名内部类的方式
Stream<UserEntity> allMatch1 = userList.stream();
boolean result3 = allMatch1.allMatch(new Predicate<UserEntity>() {
    @Override
    public boolean test(UserEntity userEntity) {
        return userEntity.getAge() < 54;
    }
});
System.out.println("allMatch使用匿名内部类的方式:" + result3);
// 2、lambda的方式
Stream<UserEntity> allMatch2 = userList.stream();
boolean result4 = allMatch2.allMatch((user) -> user.getAge() <54);
System.out.println("allMatch使用lambda的方式:" + result4);



/**
 * streamMatch匹配--anyMatch
 */
System.out.println("======anyMatch======");
// 1、匿名内部类的方式
Stream<UserEntity> anyMatch1 = userList.stream();
boolean result5 = anyMatch1.anyMatch(new Predicate<UserEntity>() {
    @Override
    public boolean test(UserEntity userEntity) {
        return userEntity.getAge() > 20;
    }
});
System.out.println("anyMatch使用匿名内部类的方式:" + result5);
// 2、lambda的方式
Stream<UserEntity> anyMatch2 = userList.stream();
boolean result6 = anyMatch2.anyMatch((user) -> user.getAge() > 20);
System.out.println("anyMatch使用lambda的方式:" + result6);


/**
 * findFirst
 */
System.out.println("======findFirst======");
Optional<UserEntity> findFirst = userList.stream().sorted(((o1, o2) -> Double.compare(o1.getAge(), o2.getAge()))).findFirst();
System.out.println("findFirst:" + findFirst.get());

/**
 * findAny
 */
System.out.println("======findAny======");
Optional<UserEntity> findAny = userList.stream().filter(userEntity -> userEntity.getName().equalsIgnoreCase("zhangsan")).findAny();
System.out.println("findAny:" + findAny.get());

/**
 * max
 */
System.out.println("======max======");
Optional<Integer> max = userList.stream().map(UserEntity::getAge).max(Double::compare);
System.out.println("max:" + max);

/**
 * min
 */
System.out.println("======min======");
Optional<Integer> min = userList.stream().map(UserEntity::getAge).min(Double::compare);
System.out.println("min:" + min);

注意:流进行了终止操作后不能再次使用!

4.2 归约

方法描述
reduce(T iden, BinaryOperator b)可以将流中元素反复结合起来,得到一个值。 返回 T
reduce(BinaryOperator b)可以将流中元素反复结合起来,得到一个值。返回 Optional< T >
/**
 * stream将reduce求和--基本数据类型
 */
System.out.println("======reduce——基本数据类型======");
// 1、使用匿名内部类的方式
Stream<Integer> integerStream1 = Stream.of(10, 30, 80, 60, 10, 70);
Optional<Integer> reduce = integerStream1.reduce(new BinaryOperator<Integer>() {
    @Override
    public Integer apply(Integer integer, Integer integer2) {
        return integer + integer2;
    }
});
System.out.println(reduce.get());
// 2、使用lambda的方式
Stream<Integer> integerStream2 = Stream.of(10, 30, 80, 60, 10, 70);
Optional<Integer> reduce2 = integerStream2.reduce((a1, a2) -> a1 + a2);
System.out.println(reduce2.get());



/**
 * stream将reduce求和--对象
 */
System.out.println("======reduce——对象======");
// 1、使用匿名内部类的方式
// 1、使用匿名内部类的方式
Stream<UserEntity> objStream1 = userEntities.stream();
Optional<UserEntity> reduce3 = objStream1.reduce(new BinaryOperator<UserEntity>() {
    @Override
    public UserEntity apply(UserEntity userEntity, UserEntity userEntity2) {
        userEntity.setAge(userEntity.getAge() + userEntity2.getAge());
        return userEntity;
    }
});
System.out.println(reduce3.get().getAge());
// 2、使用lambda的方式
Stream<UserEntity> objStream2 = userEntities.stream();
Optional<UserEntity> reduce4 = objStream2.reduce((user1, user2) -> {
    user1.setAge(user1.getAge() + user2.getAge());
    return user1;
});
System.out.println(reduce4.get().getAge());

4.3 收集

方法描述
collect(Collector c)将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法

Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下:

方法返回类型描述
toListList< T >把流中元素收集到List
toSetSet< T >把流中元素收集到Set
toCollectionCollection< T >把流中元素收集到创建的集合
countingLong计算流中元素的个数
summingIntInteger对流中元素的整数属性求和
averagingIntDouble计算流中元素Integer属性的平均值
summarizingIntIntSummaryStatistics收集流中Integer属性的统计值。 如:平均值
joiningString连接流中每个字符串
maxByOptional< T >根据比较器选择最大值
minByOptional< T >根据比较器选择最小值
reducing归约产生的类型从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值
collectingAndThen转换函数返回的类型包裹另一个收集器,对其结果转换函数
groupingByMap<K, List< T >>根据某属性值对流分组,属性为K,结果为V
partitioningByMap<Boolean, List< T >>根据true或false进行分区
/**
 * collect——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法。
 */
// toList():把流中元素收集到 List
System.out.println("======toList()======");
List<String> collectList = userList.stream().map(UserEntity::getName).collect(Collectors.toList());
collectList.forEach(System.out::println);


// toSet():把流中元素收集到 Set
System.out.println("======toSet()======");
Set<String> collectSet = userList.stream().map(UserEntity::getName).collect(Collectors.toSet());
collectSet.forEach(System.out::println);


// toCollection():把流中元素收集到创建的集合
System.out.println("======toCllection()======");
HashSet<String> collectHashSet = userList.stream().map(UserEntity::getName).collect(Collectors.toCollection(HashSet::new));
collectHashSet.forEach(System.out::println);


// counting():计算流中元素的个数
System.out.println("======counting()======");
Long collectLong = userList.stream().collect(Collectors.counting());
System.out.println("流中元素的个数:" + collectLong);


// summingInt():对流中元素的整数属性求和
System.out.println("======summingInt()======");
Integer summingInt = userList.stream().collect(Collectors.summingInt(UserEntity::getAge));
System.out.println("对流中的整数属性求和:" + summingInt);


// summarizingInt():收集流中Integer属性的统计值。 如:平均值
System.out.println("======summarizingInt()======");
IntSummaryStatistics intSummaryStatistics = userList.stream().collect(Collectors.summarizingInt(UserEntity::getAge));
System.out.println("平均值:" + intSummaryStatistics.getAverage());
System.out.println("最大值:" + intSummaryStatistics.getMax());


// joining():连接流中每个字符串("以什么符号分割", "以什么符号开头", "以什么符号结尾")
System.out.println("======joining()======");
String joiningStr = userList.stream().map(UserEntity::getName).collect(Collectors.joining(",", "---", "---"));
System.out.println(joiningStr);


// maxBy():根据比较器选择最大值
System.out.println("======maxBy()======");
Optional<Integer> collectMaxBy = userList.stream().map(UserEntity::getAge).collect(Collectors.maxBy(Integer::compare));
System.out.println(collectMaxBy.get());


// minBy():根据比较器选择最小值
System.out.println("======minBy()======");
Optional<UserEntity> collectMinBy = userList.stream().collect(Collectors.minBy(((o1, o2) -> Integer.compare(o1.getAge(), o2.getAge()))));
System.out.println(collectMinBy.get());


// reducing():从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值
System.out.println("======reducing()======");
Optional<Integer> collectReducing = userList.stream().map(UserEntity::getAge).collect(Collectors.reducing(Integer::sum));
System.out.println(collectReducing);


// groupingBy():根据某属性值对流分组,属性为K,结果为V
System.out.println("======groupingBy()======");
Map<Integer, List<UserEntity>> listMap = userList.stream().collect(Collectors.groupingBy(UserEntity::getAge));
System.out.println("根据年龄对流分组:" + listMap);
// 多级分组
Map<Integer, Map<String, List<UserEntity>>> groupMap = userList.stream().collect(Collectors.groupingBy(UserEntity::getAge, Collectors.groupingBy(u -> {
    if (u.getAge() >= 60)
        return "老年";
    else if (u.getAge() >= 35)
        return "中年";
    else
        return "成年";
})));
System.out.println(groupMap);


// partitioningBy():根据true或false进行分区
System.out.println("======partitioningBy()======");
Map<Boolean, List<UserEntity>> partitioningMap = userList.stream().collect(Collectors.partitioningBy(u -> u.getAge() >= 500));
System.out.println(partitioningMap);
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值