Java-Stream详解

Java8 Stream 数据流,大数据量下的性能效率怎么样? stream 对于终端操作,可以直接提供一个中间操作的结果,或者将结果转换为特定的 collection、array、String 等; stream 的特点 ①只能遍历一次: 数据流的从一头获取数据源,在流水线上依次对元素进行操作,当元素通过流水线,便无法再对其进行操作,可以重新在数据源获取一个新的数据流进行操作; ②采用内部迭代的方式: 对Collection进行处理,一般会使用 Iterator 遍历器的遍历方式,这是一种外部迭代; 而对于处理Stream,只要申明处理方式,处理过程由流对象自行. 阅读详情

Stream 定义

Stream是Java 8新增的接口,Stream可以认为是一个高级版本的 Iterator。

Stream跟Iterator的差别

名称含义
无存储Stream是基于数据源的对象,它本身不存储数据元素,而是通过管道将数据源的元素传递给操作。
函数式编程函数式编程:对Stream的任何修改都不会修改背后的数据源,比如对Stream执行filter操作并不会删除被过滤的元素,而是会产生一个不包含被过滤元素的新的Stream。
延迟执行Stream的操作由零个或多个中间操作(intermediate operation)和一个结束操作(terminal operation)两部分组成。只有执行了结束操作,Stream定义的中间操作才会依次执行,这就是Stream的延迟特性。
可消费性Stream只能被“消费”一次,一旦遍历过就会失效。就像容器的迭代器那样,想要再次遍历必须重新生成一个新的Stream。

Stream的操作是建立在函数式接口的组合之上的

Java8中新增的函数式接口都在java.util.function包下。这些函数式接口可以有多种分类方式。其中B开头的是二元函数,其他是一元函数

名称函数示例
一般函数Function,BiFunction例如:get方法
算子函数UnaryOperator,BinaryOperator例如:stream.reduce方法的参数
谓词函数Predicate,BiPredicate例如:stream.filter方法的参数
消费者Consumer,BiConsumer例如:set方法
供应者Supplier,BiSupplier例如:get方法

Stream的操作符

流的操作类型主要分为两种:中间操作符(Intermediate)、终端操作符(Terminal)

  1. Stream的操作由零个或多个中间操作(intermediate operation)和一个结束操作(terminal operation)两部分组成。只有执行了结束操作,Stream定义的中间操作才会依次执行,这就是Stream的延迟特性。

  2. 中间操作只是将流从一个流变成了另一个流,结束操作会生成对应的数据

  3. 这里无状态即无序,短路操作和非短路操可以理解为对应的算法操作

操作分类名称含义示例
中间操作符无状态指元素的处理不受之前元素的影响unordered() filter() map() mapToint() mapToLong() mapToDouble() flatMap() flatMapToInt() flatMapToLong() flatMapToDouble() peek()
中间操作符有状态指该操作只有拿到所有元素之后才能继续下去distinct() sorted() limit() skip()
终端操作符非短路操作指必须处理所有元素才能得到最终结果forEach() forEachOrdered() toArray() reduce() collect() max() min() count()
终端操作符短路操作指遇到某些符合条件的元素就可以得到最终结果,如 A或B,只要A为true,则无需判断B的结果anyMatch() allmatch() noneMatch() findFirst() findAny()

Stream的使用

对 Stream 的使用可以分为3步:

创建 Stream

1、使用Collection下的 stream() 和 parallelStream() 方法
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream(); //获取一个顺序流
Stream<String> parallelStream = list.parallelStream(); //获取一个并行流
2、使用Arrays 中的 stream() 方法,将数组转成流
Integer[] nums = new Integer[10];
Stream<Integer> stream = Arrays.stream(nums);
3、使用Stream中的静态方法:of()、iterate()、generate()
Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 2).limit(6);  // 不使用limit会无限生成
Stream<Double> stream3 = Stream.generate(Math::random).limit(2); // 不使用limit会无限生成
4、使用 BufferedReader.lines() 方法,将每行内容转成流
BufferedReader reader = new BufferedReader(new FileReader("D:\\stream.txt"));
Stream<String> lineStream = reader.lines();
lineStream.forEach(System.out::println);
5、使用 Pattern.splitAsStream() 方法,将字符串分隔成流
Pattern pattern = Pattern.compile(",");
Stream<String> stringStream = pattern.splitAsStream("a,b,c,d");
stringStream.forEach(System.out::println);

Intermediate(可以多次):通过一系列中间操作,对数据集进行过滤、检索等数据集的再次处理。

1、筛选与切片
名称含义参数类型
filter过滤流中的某些元素Predicate<? super T>
limit(n)获取n个元素long
skip(n)跳过n元素,配合limit(n)可实现分页long
distinct通过流中元素的 hashCode() 和 equals() 去除重复元素无
// list中大于6且小于9的元素个数
List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1, 2);
long count = list.stream().filter(x -> x > 6&&x < 9).count();
System.out.println("list中大于6且小于9的元素个数:" + count);
// 对流进行过滤去重,跳过和限制获取
Stream<Integer> newStream  = list.stream()
.filter(e -> e > 1) // 7, 6, 9, 3, 8, 2, 2
.distinct() // 7, 6, 9, 3, 8, 2
.skip(2)   //  9, 3, 8, 2
.limit(2); //  9, 3
2、映射
名称含义参数类型
map接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素Function<? super T, ? extends R>
flatMap接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流,及扁平化流,降低集合或对象的复杂程度,就像下面的例子一样把String[] 降级为String,然后在进行操作Function<? super T, ? extends Stream<? extends R>> T表示映射对象的类型,R表示返回的值是Stream的子类型

扁平化入图所示

// map
List<String> stringList = Arrays.asList("hello", "world");
List<String[]> collect = stringList.stream()
.map(str -> str.split(""))
.distinct().collect(Collectors.toList());
collect.forEach(col-> System.out.println(Arrays.toString(col)));
//[h, e, l, l, o]
//[w, o, r, l, d]

// flatMap
List<String> flatMapCollect = stringList.stream()
                .map(str -> str.split(""))
                .flatMap(Arrays::stream)
                .distinct()
                .collect(Collectors.toList());
        System.out.println(flatMapCollect);
//[h, e, l, o, w, r, d]
3、排序
名称含义参数类型
sorted()自然排序,流中元素需实现Comparable接口无
sorted(Comparator com)定制排序,自定义Comparator排序器Comparator<? super T> comparator

单个排序

// sorted()
List<Author> authors = StreamDataInit.getAuthors();
List<Author> defaultList = authors.stream().sorted().collect(Collectors.toList());
defaultList.forEach(e -> System.out.println("Id:"+ e.getId()+", Name: "+e.getName()+", Age:"+e.getAge()));
// sorted(Comparator com)
defaultList = authors.stream().sorted(Comparator.comparing(Author::getAge).reversed()).collect(Collectors.toList());
defaultList.forEach(e -> System.out.println("Id:"+ e.getId()+", Name: "+e.getName()+", Age:"+e.getAge()));

多个排序

//方法1:先对年龄进行升序,升序结果进行反转,再对班级进行降序
userList = userList.stream().sorted(Comparator.comparing(User::getAge).reversed().thenComparing(User::getClassNo, Comparator.reverseOrder())).collect(Collectors.toList());
//方法2:直接对年龄进行降序,再对班级进行降序
userList = userList.stream().sorted(Comparator.comparing(User::getAge, Comparator.reverseOrder()).thenComparing(User::getClassNo, Comparator.reverseOrder())).collect(Collectors.toList());
//方式3:先对年龄进行升序,再对班级进行升序,最后对结果进行反转
userList = userList.stream().sorted(Comparator.comparing(User::getAge).thenComparing(User::getClassNo).reversed()).collect(Collectors.toList());

总结: sorted的参数

  1. 如果只进行单个字段的升序降序排列,我们使用reversed() 或者 Comparator.reverseOrder() 都可以
  2. 如果要进行多个字段的升序降序排列,我们还是使用 Comparator.reverseOrder() 会更优雅、更好理解一些
  3. 参数形式速记
  • 无参数sorted() 这种排序相当于没有排序,他返回的是自然排序,而stream本身是无序的
  • Comparator.comparing(Author::getAge)
  • Comparator.comparing(Author::getAge).reversed()
  • Comparator.comparing(User::getAge, Comparator.reverseOrder())
  • Comparator.comparing(User::getAge, Comparator.reverseOrder()).thenComparing(User::getName, Comparator.reverseOrder())
4、消费
  • peek:如同于map,能得到流中的每一个元素。但map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,没有返回值。
  • peek:如同于forEach,peek是中间操作,而forEach是终端操作
Student s1 = new Student("aa", 10);
Student s2 = new Student("bb", 20);
List<Student> studentList = Arrays.asList(s1, s2);
  
studentList.stream()
.peek(o -> o.setAge(100))
.forEach(System.out::println);
  
//结果:
Student{name='aa', age=100}
Student{name='bb', age=100}

Terminal(只有一次):通过最终(terminal)方法完成对数据集中元素的最终处理。

1、 匹配、聚合操作
名称含义参数类型
allMatch接收一个 Predicate 函数,当流中每个元素都符合该断言时才返回true,否则返回falsePredicate
noneMatch接收一个 Predicate 函数,当流中每个元素都不符合该断言时才返回true,否则返回falsePredicate
anyMatch接收一个 Predicate 函数,只要流中有一个元素满足该断言则返回true,否则返回falsePredicate
findFirst返回流中第一个元素无
findAny返回流中的任意元素无
count返回流中元素的总个数无
max返回流中元素最大值Comparator<? super T>
min返回流中元素最小值Comparator<? super T>
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
  
boolean allMatch = list.stream().allMatch(e -> e > 10); //false
boolean noneMatch = list.stream().noneMatch(e -> e > 10); //true
boolean anyMatch = list.stream().anyMatch(e -> e > 4); //true
  
Integer findFirst = list.stream().findFirst().get(); //1
Integer findAny = list.stream().findAny().get(); //1
  
long count = list.stream().count(); //5
Integer max = list.stream().max(Integer::compareTo).get(); //5
Integer min = list.stream().min(Integer::compareTo).get(); //1 
2、 规约操作

规约操作又被称作折叠操作,是通过某个连接动作将所有元素汇总成一个汇总结果的过程。元素求和、求最大值或最小值、求出元素总个数、将所有元素转换成一个列表或集合,都属于规约操作。_Stream_类库有两个通用的规约操作reduce()和collect(),也有一些为简化书写而设计的专用规约操作,比如sum()、max()、min()、count()等。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

/**============================================================使用reduce求所有作者年龄的和===**/
 List<Author> authors = StreamDataInit.getAuthors();
 Integer sum = authors.stream()
         .distinct()
         .map(author -> author.getAge())
         .reduce(0, (result, element) -> result + element);
 System.out.println(sum);
 /**============================================================使用reduce求所有作者中年龄的最大值===**/
 Integer reduce1 = authors.stream()
         .map(author -> author.getAge())
         .reduce(Integer.MIN_VALUE, (result, element) -> result < element ? element : result);
 System.out.println(reduce1);
 /**============================================================使用reduce求所有作者中年龄的最小值===**/
 Integer reduce2 = authors.stream()
         .map(author -> author.getAge())
         .reduce(Integer.MAX_VALUE, (result, element) -> result > element ? element : result);
 System.out.println(reduce2);
 /**============================================================用一个参数的重载方法去求最小值代码===**/
 Optional<Integer> reduce = authors.stream()
         .map(author -> author.getAge())
         .reduce(new BinaryOperator<Integer>() {
             @Override
             public Integer apply(Integer result, Integer element) {
                 return result > element ? element : result;
             }
         });
 reduce.ifPresent(age -> System.out.println(age));
 /**============================================================求和方式===**/
 List<Integer> list = Arrays.asList(1, 3, 2, 8, 11, 4);
 // 求和方式1
 Optional<Integer> sum1 = list.stream().reduce((x, y) -> x + y);
 // 求和方式2
 Optional<Integer> sum2 = list.stream().reduce(Integer::sum);
 // 求和方式3
 Integer sum3 = list.stream().reduce(0, Integer::sum);
 System.out.println("list求和:" + sum1.get() + "," + sum2.get() + "," + sum3);
 // 求和方式4
 Integer sum4 = authors.stream().collect(Collectors.reducing(0, Author::getAge, (i, j) -> (i + j - 5000)));
 System.out.println("作家扣税薪资总和:" + sum4);
 // 求和方式5
 Optional<Integer> sum5 = authors.stream().map(Author::getAge).reduce(Integer::sum);
 System.out.println("作家薪资总和:" + sum5.get());
 // 求和方式6
 BigDecimal sumSalary = authors.stream()
         .map(Author::getSalary)
         .reduce(BigDecimal.ZERO, BigDecimal::add);
 System.out.println("工资之和:"+sumSalary);
 /**============================================================求乘积===**/
 Optional<Integer> product = list.stream().reduce((x, y) -> x * y);
 /**============================================================求最大值===**/
 // 求最大值方式1
 Optional<Integer> max1 = list.stream().reduce((x, y) -> x > y ? x : y);
 // 求最大值写法2
 Integer max2 = list.stream().reduce(1, Integer::max);
 System.out.println("list求积:" + product.get());
 System.out.println("list求和:" + max1.get() + "," + max2);
3、 收集操作

collect:接收一个Collector实例,将流中元素收集成另外一个数据结构。Collector<T, A, R> 是一个接口,有以下5个抽象方法:

名称含义
Supplier supplier()创建一个结果容器A
BiConsumer<A, T> accumulator()消费型接口,第一个参数为容器A,第二个参数为流中元素T
BinaryOperator combiner()函数接口,该参数的作用跟上一个方法(reduce)中的combiner参数一样,将并行流中各 个子进程的运行结果(accumulator函数操作后的容器A)进行合并
Function<A, R> finisher()函数式接口,参数为:容器A,返回类型为:collect方法最终想要的结果R
Set characteristics()返回一个不可变的Set集合,用来表明该Collector的特征。有以下三个特征CONCURRENT:表示此收集器支持并发。UNORDERED:表示该收集操作不会保留流中元素原有的顺序。IDENTITY_FINISH:表示finisher参数只是标识而已,可忽略。
public class CollectorCustom {
    public static void main(String[] args) {
        Set<Integer> collect = Arrays.asList(1, 2, 3, 3, 4, 5, 6).stream().collect(new MyCollector<Integer>());
        System.out.println(collect);
    }
    public static class MyCollector<T> implements Collector<T, Set<T>, Set<T>> {
        @Override
        public Supplier<Set<T>> supplier() {
            System.out.println("MyCollector.supplier");
            return HashSet::new;  -->我们提供一个HashSet
        }
        @Override
        public BiConsumer<Set<T>, T> accumulator() {
            System.out.println("MyCollector.accumulator");
            return Set::add; -->我们处理Set 和流中元素T的关系
     
        }
        @Override
        public BinaryOperator<Set<T>> combiner() {
            System.out.println("MyCollector.combiner");
            return (st1, st2) -> {
                st1.addAll(st2);
                return st1;   ->如果是并发流,创建了多个容器,我们处理多个容器间的关系
            };
        }
        @Override
        public Function<Set<T>, Set<T>> finisher() {
            System.out.println("MyCollector.finisher");
            return Function.identity();  -> 处理 容器和最终返回的规约,我们选择都是返回Set<T>

        }
        @Override
        public Set<Characteristics> characteristics() {
            System.out.println("MyCollector.characteristics");
            return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH, UNORDERED));
            --> 当我们使用了 IDENTITY_FINISH ,其实就不用再写finisher();不知道你明不明白?
            --> UNORDERED 不追求顺序,我们毕竟用的HashSet
        }
    }
}

4、collect实战
(1)收集 Stream 流中的数据到集合中
//1.收集数据到list集合中
stream.collect(Collectors.toList())
//2.收集数据到set集合中
stream.collect(Collectors.toSet())
//3.收集数据到指定的集合中
Collectors.toCollection(Supplier<C> collectionFactory)
stream.collect(Collectors.joining())
/**
 * 收集Stream流中的数据到集合中
 * 备注:切记Stream流只能被消费一次,流就失效了
 * 如下只是示例代码
 */
public class CollectDataToCollection{

    public static void main(String[] args) {
        //Stream 流
        Stream<String> stream = Stream.of("aaa", "bbb", "ccc", "bbb");
        //收集流中的数据到集合中
        //1.收集流中的数据到 list
        List<String> list = stream.collect(Collectors.toList());
        System.out.println(list);

        //2.收集流中的数据到 set
        Set<String> collect = stream.collect(Collectors.toSet());
        System.out.println(collect);

        //3.收集流中的数据(ArrayList)(不收集到list,set等集合中,而是)收集到指定的集合中
        ArrayList<String> arrayList = stream.collect(Collectors.toCollection(ArrayList::new));
        System.out.println(arrayList);

        //4.收集流中的数据到 HashSet
        HashSet<String> hashSet = stream.collect(Collectors.toCollection(HashSet::new));
        System.out.println(hashSet);
    }
}
(2)收集 Stream 流中的数据到数组中
//1.使用无参,收集到数组,返回值为 Object[](Object类型将不好操作)
Object[] toArray();
//2.使用有参,可以指定将数据收集到指定类型数组,方便后续对数组的操作
<A> A[] toArray(IntFunction<A[]> generator);
/**
 * 收集Stream流中的数据到数组中
 * 备注:切记Stream流只能被消费一次,流就失效了
 * 如下只是示例代码
 */
public class CollectDataToArray{

    public static void main(String[] args) {
        //Stream 流
        Stream<String> stream = Stream.of("aaa", "bbb", "ccc", "bbb");
         
        //2.1 使用 toArray()无参
        Object[] objects = stream.toArray();
        for (Object o: objects) {//此处无法使用.length() 等方法
            System.out.println("data:"+o);
        }

        //2.2 使用有参返回指定类型数组
        //无参不好的一点就是返回的是 Object[] 类型,操作比较麻烦.想要拿到长度,Object是拿不到长度的
        String[] strings = stream.toArray(String[]::new);
        for(String str : strings){
            System.out.println("data:"+str + ",length:"+str.length());
        }
    }
}
(3)Stream流中数据聚合/分组/分区/拼接操作
//最大值
Collectors.maxBy();
//最小值
Collectors.minBy();
//总和
Collectors.summingInt();/Collectors.summingDouble();/Collectors.summingLong();
//平均值
Collectors.averagingInt();/Collectors.averagingDouble();/Collectors.averagingLong();
//总个数
Collectors.counting();
5、聚合操作
/**
 * Stream流数据--聚合操作
 * 备注:切记Stream流只能被消费一次,流就失效了
 * 如下只是示例代码
 * @author liuzebiao
 * @Date 2020-1-10 13:37
 */
public class CollectDataToArray{

    public static void main(String[] args) {
        Stream<Student> studentStream = Stream.of(
                new Student("赵丽颖", 58, 95),
                new Student("杨颖", 56, 88),
                new Student("迪丽热巴", 56, 99),
                new Student("柳岩", 52, 77)
        );

        //聚合操作
        //获取最大值(Stream流 max()方法亦可)
        //max()方法实现
        //Optional<Student> max = studentStream.max((s1, s2) -> s1.getScore() - s2.getScore());
        //(聚合)实现
        Optional<Student> max = studentStream.collect(Collectors.maxBy((s1, s2) -> s1.getScore() - s2.getScore()));
        System.out.println("最大值:"+max.get());

        //获取最小值(Stream流 min()方法亦可)
        //min()方法实现
        //Optional<Student> min = studentStream.max((s1, s2) -> s2.getScore() - s1.getScore());
        //(聚合)实现
        Optional<Student> min = studentStream.collect(Collectors.minBy((s1, s2) -> s1.getScore() - s2.getScore()));
        System.out.println("最小值:"+min.get());

        //求总和(使用Stream流的map()和reduce()方法亦可求和)
        //map()和reduce()方法实现
        //Integer reduce = studentStream.map(s -> s.getAge()).reduce(0, Integer::sum);
        //(聚合)简化前
        //Integer ageSum = studentStream.collect(Collectors.summingInt(s->s.getAge()));
        //(聚合)使用方法引用简化
        Integer ageSum = studentStream.collect(Collectors.summingInt(Student::getAge));
        System.out.println("年龄总和:"+ageSum);

        //求平均值
        //(聚合)简化前
        //Double avgScore = studentStream.collect(Collectors.averagingInt(s->s.getScore()));
        //(聚合)使用方法引用简化
        Double avgScore = studentStream.collect(Collectors.averagingInt(Student::getScore));
        System.out.println("分数平均值:"+avgScore);

        //统计数量(Stream流 count()方法亦可)
        //count()方法实现
        //long count = studentStream.count();
        //(聚合)统计数量
        Long count = studentStream.collect(Collectors.counting());
        System.out.println("数量为:"+count);
    }
}
6、分组操作
//接收一个 Function 参数
groupingBy(Function<? super T, ? extends K> classifier)
/**
 * Stream流数据--分组操作
 * 备注:切记Stream流只能被消费一次,流就失效了
 * 如下只是示例代码
 * @author liuzebiao
 * @Date 2020-1-10 13:37
 */
public class CollectDataToArray{

    public static void main(String[] args) {
        Stream<Student> studentStream = Stream.of(
                new Student("赵丽颖", 52, 56),
                new Student("杨颖", 56, 88),
                new Student("迪丽热巴", 56, 99),
                new Student("柳岩", 52, 53)
        );
        
        //1.按照具体年龄分组
        Map<Integer, List<Student>> map = studentStream.collect(Collectors.groupingBy((s -> s.getAge())));
        map.forEach((key,value)->{
            System.out.println(key + "---->"+value);
        });

        //2.按照分数>=60 分为"及格"一组  <60 分为"不及格"一组
        Map<String, List<Student>> map = studentStream.collect(Collectors.groupingBy(s -> {
            if (s.getScore() >= 60) {
                return "及格";
            } else {
                return "不及格";
            }
        }));
        map.forEach((key,value)->{
            System.out.println(key + "---->"+value.get());
        });

        //3.按照年龄分组,规约求每组的最大值(规约:reducing)
        Map<Integer, Optional<Student>> reducingMap = studentStream.collect(
                Collectors.groupingBy(Student::getAge, 
                        Collectors.reducing(
                                BinaryOperator.maxBy(
                                        Comparator.comparingInt(Student::getScore)
                                )
                        )
                )
        );
        reducingMap .forEach((key,value)->{
            System.out.println(key + "---->"+value);
        });
    }
}
7、多级分组操作
//接收两个参数: 1.Function 参数  2.Collector多级分组
groupingBy(Function<? super T, ? extends K> classifier,Collector<? super T, A, D> downstream) 
/**
 * Stream流数据--多级分组操作
 * 备注:切记Stream流只能被消费一次,流就失效了
 * 如下只是示例代码
 * @author liuzebiao
 * @Date 2020-1-10 13:37
 */
public class CollectDataToArray{

    public static void main(String[] args) {
        Stream<Student> studentStream = Stream.of(
                new Student("赵丽颖", 52, 95),
                new Student("杨颖", 56, 88),
                new Student("迪丽热巴", 56, 55),
                new Student("柳岩", 52, 33)
        );

        //多级分组
        //1.先根据年龄分组,然后再根据成绩分组
        //分析:第一个Collectors.groupingBy() 使用的是(年龄+成绩)两个维度分组,所以使用两个参数 groupingBy()方法
        //    第二个Collectors.groupingBy() 就是用成绩分组,使用一个参数 groupingBy() 方法
        Map<Integer, Map<Integer, Map<String, List<Student>>>> map = studentStream.collect(Collectors.groupingBy(str -> str.getAge(), Collectors.groupingBy(str -> str.getScore(), Collectors.groupingBy((student) -> {
            if (student.getScore() >= 60) {
                return "及格";
            } else {
                return "不及格";
            }
        }))));

        map.forEach((key,value)->{
            System.out.println("年龄:" + key);
            value.forEach((k2,v2)->{
                System.out.println("\t" + v2);
            });
        });
    }
}
8、分组和分区

分组和分区的区别就在:分组可以有多个组。分区只会有两个区( true 和 false)

//1.一个参数
partitioningBy(Predicate<? super T> predicate)

//2.两个参数(多级分区)
partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downstream)
/**
 * Stream流数据--多级分组操作
 * 备注:切记Stream流只能被消费一次,流就失效了
 * 如下只是示例代码
 * @author liuzebiao
 * @Date 2020-1-10 13:37
 */
public class CollectDataToArray{

    public static void main(String[] args) {
        Stream<Student> studentStream = Stream.of(
                new Student("赵丽颖", 52, 95),
                new Student("杨颖", 56, 88),
                new Student("迪丽热巴", 56, 55),
                new Student("柳岩", 52, 33)
        );

        //分区操作
        Map<Boolean, List<Student>> partitionMap = studentStream.collect(Collectors.partitioningBy(s -> s.getScore() > 60));
        partitionMap.forEach((key,value)->{
            System.out.println(key + "---->" + value);
        });
    }
}
9、拼接操作
//无参数--等价于 joining("");
joining()
//一个参数
joining(CharSequence delimiter)
//三个参数(前缀+后缀)
joining(CharSequence delimiter, CharSequence prefix,CharSequence suffix)
/**
 * Stream流数据--多级分组操作
 * 备注:切记Stream流只能被消费一次,流就失效了
 * 如下只是示例代码
 * @author liuzebiao
 * @Date 2020-1-10 13:37
 */
public class CollectDataToArray{

    public static void main(String[] args) {
        Stream<Student> studentStream = Stream.of(
                new Student("赵丽颖", 52, 95),
                new Student("杨颖", 56, 88),
                new Student("迪丽热巴", 56, 55),
                new Student("柳岩", 52, 33)
        );
        
        //拼接操作
        //无参:join()
        String joinStr1 = studentStream.map(s -> s.getName()).collect(Collectors.joining());
        System.out.println(joinStr1);
        //一个参数:joining(CharSequence delimiter)
        String joinStr2 = studentStream.map(s -> s.getName()).collect(Collectors.joining(","));
        System.out.println(joinStr2);
        //三个参数:joining(CharSequence delimiter, CharSequence prefix,CharSequence suffix)
        String joinStr3 = studentStream.map(s -> s.getName()).collect(Collectors.joining("—","^_^",">_<"));
        System.out.println(joinStr3);
    }
}
for,Iterator,Stream对集合遍历操作的时间性能的简单比较 这篇文章目的是为了简单地比较for,迭代器,stream(parallelStream)三种对集合的遍历操作的时间性能 阅读详情

相关推荐

Java Stream详解

如果对一个对象进行操作,比如Person中有姓名和年龄,这时候通过peek修改了其中的年龄,那么这个值会被改变。以Boolean为 key的分组,key为Boolean值,后面是value值,属于Map集合。类似Stream中的map,先操作(此操作会可以改变其类似),之后在做处理。不解释,放在最后,如果使用了forEach那么后面就无法再跟其它流函数。先计算平均年龄,之后将计算结果转为整数,可以理解为:先收集之后再干嘛。求总数,和SQL中count类似。将元素输出到 Map。求和转成double。

Bunny的博客 951

Stream流和Iterator以及Optional

Iterator Java Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法,可用于迭代 ArrayList 和 HashSet 等集合,foreach底层也是一个迭代器,集合的的删除操作要在迭代器中进行操作,拿ArrayList举例,底层是数组结构,在进行元素删除的时候,后边的元素要前移一位,这时候对应索引上的值发生了变化,如下,若在循环中进行删除操作之后,当前索引位置i上的值被删除,i+1索引位置上的值会自动移到i上,i+1的值变成i+2索引位置的值,在进行i+1索引位置的值删除的是

m0_63670824的博客 2360

Java Stream流的详解

Stream作为Java8的一大亮点,它与java.io包里的InputStream和OutputStream是完全不同的概念。Java8中的Stream是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregateoperation),或者大批量数据操作(bulkdataoperation)。StreamAPI借助于同样新出现的Lambda表达式,而且使用并发模式,极大的提高编程效率和程序可读性。...

流楚丶格念的博客 3342

java8工具类Stream得用法

方法生成的 Stream 对象中的数据的数量是无限的(即,你向 Stream 对象每次『要』一个对象时它都会每次生成一个返回给你,从而达到『无限个』的效果),所以,会结合。方法生成的 Stream 对象中的数据的数量是无限的(即,你向 Stream 对象每次『要』一个对象时它都会每次生成一个返回给你,从而达到『无限个』的效果),所以,会结合。方法会返回一个传统风格的迭代器,结合 Java SE 阶段的『集合框架』部分的知识点,通过 Iterator 对象你就可以遍历访问到 Stream 中的每一个元素。

行云的博客 2082

LED背光驱动电路解析:从MP3394芯片到液晶屏灯管控制

本文深入解析了以MP3394芯片为核心的LED背光驱动电路工作原理。从升压电路的能量转换到多路LED的均流控制,详细阐述了其作为液晶屏背光“大脑”的关键作用,并提供了黑屏、闪屏、亮度不均等常见故障的实战检修思路与排查方法。

agile9scrum的博客 815

【Spring源码三千问】哪些循环依赖问题Spring解决不了?

哪些循环依赖问题Spring解决不了?前言版本约定正文场景一: prototype 类型的循环依赖场景二: constructor 注入的循环依赖场景三:Proxy 类型的 Bean 的循环依赖小结 系列博文: 【老王读Spring IoC-0】Spring IoC 引入 【老王读Spring IoC-1】IoC 之控制反转引入 【老王读Spring IoC-2】IoC 之 BeanDefinition 扫描注册 【老王读Spring IoC-3】Spring bean 的创建过程 【老王读Spring I

老王的专栏 7318

Java中的Stream流详解

文章目录1、Stream API概述2、Stream 的操作三个步骤3、创建Stream的方式4、中间操作筛选与切片映射排序5、终止操作查找与匹配归约收集Collectors 中的方法 1、Stream API概述 Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。 使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询,也可以使用 Stream API 来并行执行操作。 简而言之,Stre

weixin_45082647的博客 4824

特斯拉 Model 3解析(九)特斯拉 Model 3 自动驾驶域控制器硬件架构

硬件层:车规级高密度主板 → PI/SI优化到极致传感器层:三目摄像头主导视觉,雷达补充冗余,超声波保证近距设计理念:依靠芯片算力最大化视觉潜力,而不是堆传感器这套思路的优点是:成本可控、量产快、迭代快。缺点是:极端场景下感知鲁棒性不足。纯视觉方案短期可行,但中长期必然要重新引入高分辨率雷达甚至固态LiDAR作为冗余。电源/信号完整性会越来越关键,未来域控板设计会越来越像数据中心服务器。

weixin_43199439的博客 1784

Java Stream 流详解

在某些情况下,可能需要自定义实现 Stream。这通常涉及实现接口来定义迭代器行为,然后使用方法创建 Stream。

开心杨的个人博客 1589

用LightRAG+Ollama搭建本地知识库:从文档上传到智能问答的完整流程

本文详细介绍了如何利用LightRAG与Ollama构建企业级本地知识库,涵盖从文档预处理到智能问答的完整流程。通过实战案例展示,该方案能高效处理海量文档,实现语义搜索与知识图谱关联分析,显著提升信息检索效率。特别适合金融、医疗等领域的技术团队快速搭建智能知识管理系统。

weixin_42535461的博客 184

Android Binder的两三事--基于Android14源码

Android14-Framework-Binder

保持专注,保持热爱 1140

java stream详解

Stream数据源 1. Collection 2. Arrays Stream流处理逻辑 数据源(datasource) --> 数据转换(中间操作) -->数据转换(中间操作) -->执行操作获取结果(终止操作) Stream创建 通过collection创建( collection.stream() or collection.parallelStream()方法) Collection<String> collection = new ArrayList<&

marylgao技术专栏 4764

华为OD机试 - 机器人活动区域(Java 双机位C卷 200分)

现有一个机器人,可放置于 M × N的网格中任意位置,每个网格包含一个非负整数编号。之后M行表示网格数值,每行N个数值(数值大小用k表示),数值间用单个空格分隔,行首行尾无多余空格。说明:图中绿色区域,相邻网格差值绝对值都小于等于1,且为最大区域,对应网格点数目为6。M、N、k均为整数,且1

学Java,找哪吒 915

【Java Stream详解】

Java Stream 是 Java 8 引入的一项强大特性,主要用于处理集合数据。它提供了类似于函数式编程的方式,使代码更加简洁、易读,同时提高了效率。本文将详细介绍 Stream 的基本概念、常用操作、使用场景。Stream过滤、映射、排序、统计、收集等。Stream 提供了链式操作方式,使代码简洁且易读。Stream 提供了简洁、易读的集合操作方式,常用于数据过滤、映射、聚合等操作。中间操作返回新的流对象,不执行终端操作不会触发计算。终端操作触发流的计算并返回结果。并行流。

武帝为此的博客 1887

大模型——AI对话四象限

{ "摘要": "文章揭示了90%的人不会有效与AI沟通的问题,指出简单粗暴的提问只能得到标准答案。作者提出'AI对话四象限'模型:1)双方都懂时提效;2)AI懂但需学会分层提问;3)共同探索未知领域;4)向AI传授独家知识。强调沟通技巧的重要性,认为会提问的人不会被AI替代。最后呼吁读者尝试四象限思维,与AI碰撞火花。" }

308

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

java stream order by_Java Stream 使用详解

Stream是 Java 8新增加的类,用来补充集合类。Stream代表数据流,流中的数据元素的数量可能是有限的,也可能是无限的。Stream和其它集合类的区别在于:其它集合类主要关注与有限数量的数据的访问和有效管理(增删改),而Stream并没有提供访问和管理元素的方式,而是通过声明数据源的方式,利用可计算的操作在数据源上执行,当然BaseStream.iterator()和BaseStream...

weixin_29876591的博客 6961

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Java Stream流详解

Stream流是Java 8引入的一种处理数据集合的API,它允许以声明式方式处理数据集合,让开发者能够写出更加简洁、高效的代码。Stream流的设计初衷是提供一种函数式编程的方式来处理集合,使代码更具可读性,并可以利用多核架构实现并行操作。Stream流不是一种数据结构,它只是数据源的一个视图,不会存储数据,也不会修改源数据。通常,Stream流的操作是延迟执行的,这意味着它们直到需要结果时才会计算。

yk_dflkg的博客 2420

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Java中Stream流详解

Java中的Stream是Java 8引入的一种新的API,用于处理集合或数组中的数据,提供了一种简洁且高效的方式来进行各种操作,如过滤、排序、映射、汇总等。Stream不存储数据,它更像是一个高级迭代器,通过一系列流水线操作来处理数据。中间操作和终端操作。

welcome 6403

Java的Stream详解

comparing(Person::getCity, Comparator.nullsLast(String::compareTo))//定义比较类先是通过city排序,对于null的排到最后//然后通过年龄进行比较.sorted(byCityThenAge)//通过比较类进行排序简洁性和可读性:代码更简洁,避免了显式的循环。函数式编程支持:通过高阶函数提供更高的灵活性和可重用性。并行处理:轻松使用实现并行处理,提高性能。惰性计算和延迟求值:避免不必要的计算,提高性能。

2303_80195175的博客 1029

Java Stream原理

文章目录一、简介二、原理2.1 如何保存操作?2.2 如何形成流?2.3 如何执行?参考 一、简介 流操作可以分为中间操作和结束操作。 中间操作分为:无状态操作(map、fliter、skip等等)和有状态操作(需要得到所有元素才能进行,例如limit、sorted、distinct) 结束操作分为:短路操作(遇到符合条件的元素就终止,如findFirst、anyMatch、findAny)和非短路操作(需要得到所有元素才能进行,如collect、max、count、forEach等) Stream的实

sinat_38705282的博客 4174

Java Stream功能详解

java8 Stream详解

变个魔术 1050

Java8中的Stream详解

目录 一.什么是Stream 1.Stream的特征 2.Stream的原理 3.Stream和Collections的区别 4.Stream的操作 5.不使用Stream和使用Stream对比  二.常见应用场景 1.生成流  2.forEach 3.map 4.filter 5.limit 6.sorted 7.Collectors 8.统计 一.什么是Stre...

lcgoing的博客 1044

java Stream debug 调试

平时有时候需要Stream出问题又不知道哪里的时候想调试但是不会调试怎么办呢?今天就来说说java的Stream是怎么调试的。官方的链接地址是:https://www.jetbrains.com/help/idea/analyze-java-stream-operations.html,如果英文好的话也可以直接看英文的。 先写一个简单的Stream方法 public class StreamTes...

syr1136877833的博客 8112
上一篇: Clickhosue 强大的函数,argMin() 和argMax()函数
下一篇: jinjava学习实战
架构师的清醒
博客等级 码龄14年 291粉丝 397原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值