安陆网站建设推广想要推广网页
目 录
一、概述
二、创建 Stream 的三种方式
1.Collection 接口提供的方法
2.Arrays 类提供的方法
3.Stream 接口提供的方法
三、顺序流与并行流
四、中间操作
1.筛选(filter)
2.映射(map)
3.去重(distinct)
4.排序(sorted)
5.合并(concat)
6.跳过(skip)
7.截断(limit)
五、终止操作
1.遍历(forEach)
2.匹配(match)
3.归约(reduce)
4.收集(collect)
(1)归集(toList / toSet / toMap)
(2)统计(counting / averaging)
(3)分组(groupingBy)
(4)接合(joining)
一、概述
- 从 jdk 8 开始,Java 引入了全新的 Stream API,它将函数式编程的风格运用到了 Java 中,允许开发者在不改变数据源的情况下对集合进行操作;
- Collection 是静态的内存数据结构,强调的是数据。而 Stream API 是与集合相关的计算操作,强调的是计算。即 Collection 面向内存,Stream API 面向 CPU;
- 步骤:
- 创建操作:通过数据源获取一个 Stream 对象;
- 中间操作:对数据源的数据进行处理,返回一个 Stream 对象,因此可以链式操作;
- 终止操作:执行终止操作时,才会真正执行中间操作,并返回一个计算完成的结果。
- 特点:
- 不会存储对象,只能对元素进行计算;
- 不会改变数据对象,可能会返回一个持有结果的新 Stream;
- Stream 上的操作属于延迟操作,只有等用户真正需要结果的时候才会执行;
- 一旦执行终止操作,就不能再调用其他的中间操作或终止操作。
二、创建 Stream 的三种方式
1.Collection 接口提供的方法
public class CollectionCreate {public static void main(String[] args) {ArrayList<String> arrayList = new ArrayList<>();arrayList.add("《诗经》");arrayList.add("《尚书》");arrayList.add("《礼记》");arrayList.add("《周易》");arrayList.add("《春秋》");// 顺序流,单线程Stream<String> stream = arrayList.stream();System.out.println(stream); // java.util.stream.ReferencePipeline$Head@4eec7777// 并行流,计算时自动启动多线程Stream<String> parallelStream = arrayList.parallelStream();System.out.println(parallelStream); // java.util.stream.ReferencePipeline$Head@3b07d329}
}
2.Arrays 类提供的方法
public class ArraysCreate {public static void main(String[] args) {String[] musics = {"《姑娘别哭泣》", "《谁》", "《遇见》", "《轻红》", "《可可托海的牧羊人》"};Stream<String> stream = Arrays.stream(musics);System.out.println(stream); // java.util.stream.ReferencePipeline$Head@4eec7777}
}
3.Stream 接口提供的方法
public class StreamCreate {public static void main(String[] args) {Stream<String> cinema = Stream.of("《这个杀手不太冷》", "《教父》", "《终结者》", "《建军大业》");System.out.println(cinema); // java.util.stream.ReferencePipeline$Head@4eec7777}
}
三、顺序流与并行流
顺序流对 Stream 对象处理是单线程的,效率较低。
若 Stream 流中处理数据没有顺序要求,且希望可以并行处理数据,则可以使用并行流来处理,从而提高效率。
将顺序流转换为并行流,只需要调用 Stream 提供的 parallel 方法进行转换,无需编写任何多线程代码。
public class TransportParallel {public static void main(String[] args) {Stream<String> country = Stream.of("中国", "俄罗斯", "美国", "英国", "法国");System.out.println(country.isParallel()); // falseStream<String> parallel = country.parallel();System.out.println(parallel.isParallel()); // trueSystem.out.println(country == parallel); // true}
}
四、中间操作
1.筛选(filter)
按照一定规则校验流中元素,将符合条件的元素提取到新的流中操作。该操作使用 Stream 接口提供的 【Stream<T> filter(Predicate<? super T> predicate)】方法实现。
public class Student {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
public class FilterTest {public static void main(String[] args) {Student s1 = new Student("张三", 18);Student s2 = new Student("李四", 23);Student s3 = new Student("王五", 9);Student s4 = new Student("赵六", 45);Student s5 = new Student("孙七", 13);ArrayList<Student> arrayList = new ArrayList<>();arrayList.add(s1);arrayList.add(s2);arrayList.add(s3);arrayList.add(s4);arrayList.add(s5);// 过滤出成年学生// filter 是 Stream 的一个中间操作,返回一个 Stream 对象// forEach 是 Stream 的一个终止操作// 匿名内部类/*arrayList.stream().filter(new Predicate<Student>() {@Overridepublic boolean test(Student student) {return student.getAge() >= 18;}}).forEach(new Consumer<Student>() {@Overridepublic void accept(Student student) {System.out.println(student);}});*/// Lambda 表达式arrayList.stream().filter(student -> student.getAge() >= 18).forEach(System.out::println);}
}
2.映射(map)
将一个流的元素按照一定映射规则映射到另一个流中。该操作使用了 Stream 接口提供的【Stream map(Function<? super T, ? > mapper)】方法实现。
可以实现将多个集合中的元素映射到另一个流中。该操作使用了 Stream 接口提供的【Stream flatMap(Function<? super T, ? extends Stream<R>> mapper)】方法实现。
public class MapTest {public static void main(String[] args) {Stream<String> stream = Stream.of("A", "BC", "DEF");// 全部转换为小写字母// 匿名内部类/*stream.map(new Function<String, String>() {@Overridepublic String apply(String s) {return s.toLowerCase();}}).forEach(new Consumer<String>() {@Overridepublic void accept(String string) {System.out.println(string);}});
*/// Lambda 表达式stream.map(str -> str.toLowerCase()).forEach(System.out::println);}
}
public class FlatMapTest {public static void main(String[] args) {Student s1 = new Student("明世隐", 20);Student s2 = new Student("李元芳", 18);Student s3 = new Student("蔡文姬", 6);Student s4 = new Student("伽罗", 22);Student s5 = new Student("澜", 27);ArrayList<Student> arrayList1 = new ArrayList<>();arrayList1.add(s1);arrayList1.add(s2);ArrayList<Student> arrayList2 = new ArrayList<>();arrayList2.add(s3);arrayList2.add(s4);arrayList2.add(s5);Stream<ArrayList<Student>> stream = Stream.of(arrayList1, arrayList2);// flatMap()方法,将多个集合中的元素放到一个 Stream,形成一个新的流// 匿名内部类/*stream.flatMap(new Function<ArrayList<Student>, Stream<Student>>() {@Overridepublic Stream<Student> apply(ArrayList<Student> students) {return students.stream();}}).forEach(new Consumer<Student>() {@Overridepublic void accept(Student student) {System.out.println(student);}});*/// lambda 表达式stream.flatMap(ArrayList<Student>::stream).forEach(System.out::println);}
}
3.去重(distinct)
去除重复的元素,底层使用了 hashCode() 和 equals(Object obj) 判断元素是否相等。该操作使用了 Stream 接口提供的【Stream distinct()】方法实现。
public class Student {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
}
public class DistinctTest {public static void main(String[] args) {Student s1 = new Student("小明", 23);Student s2 = new Student("小红", 23);Student s3 = new Student("小王", 23);Student s4 = new Student("小李", 23);Student s5 = new Student("小明", 18);Student s6 = new Student("小红", 23);ArrayList<Object> arrayList = new ArrayList<>();arrayList.add(s1);arrayList.add(s2);arrayList.add(s3);arrayList.add(s4);arrayList.add(s5);arrayList.add(s6);// distinct 去重arrayList.stream().distinct().forEach(System.out::println);}
}
4.排序(sorted)
使用 Stream 接口中的【Stream sorted()】方法,用于对元素的自然排序,使用该方法则元素对应的类必须实现 Comparable 接口。
使用 Stream 接口中的【Stream sorted(Comparator<? super T> comparator)】方法,用于对元素的指定排序,如此可以对一个类实现多种排序规则。
public class Student implements Comparable<Student> {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic int compareTo(Student o) {return this.getAge() - o.getAge();}
}
public class NaturalSorted {public static void main(String[] args) {Student s1 = new Student("光光", 18);Student s2 = new Student("冬冬", 2);Student s3 = new Student("球球", 16);Student s4 = new Student("红红", 23);Student s5 = new Student("白白", 45);Student[] students = {s1, s2, s3, s4, s5};Stream<Student> stream = Arrays.stream(students);stream.sorted().forEach(System.out::println);}
}
public class Student {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
public class SpecifySorted {public static void main(String[] args) {Student s1 = new Student("光光", 18);Student s2 = new Student("冬冬", 2);Student s3 = new Student("球球", 16);Student s4 = new Student("红红", 23);Student s5 = new Student("白白", 45);ArrayList<Student> students = new ArrayList<>();students.add(s1);students.add(s2);students.add(s3);students.add(s4);students.add(s5);Stream<Student> stream = students.stream();stream.sorted((o1, o2) -> o1.getAge() - o2.getAge()).forEach(System.out::println);}
}
5.合并(concat)
将两个 Stream 合并成一个 Stream。该操作使用 Stream 接口提供的【public static Stream concat(Stream<? extends T> a, Stream<? extends T> b)】方法实现。
public class ConcatTest {public static void main(String[] args) {Student s1 = new Student("明世隐", 20);Student s2 = new Student("李元芳", 18);Student s3 = new Student("蔡文姬", 6);Student s4 = new Student("伽罗", 22);Student s5 = new Student("澜", 27);Stream<Student> stream1 = Stream.of(s1, s2, s3);Stream<Student> stream2 = Stream.of(s4, s5);Stream<Student> concat = Stream.concat(stream1, stream2);concat.forEach(System.out::println);}
}
6.跳过(skip)
跳过是跳过 n 个元素开始操作。该操作使用 Stream 接口提供的【Stream skip(long n)】方法实现。
public class SkipTest {public static void main(String[] args) {Stream<Integer> stream = Stream.of(1, 3, 5, 7, 9, 2, 4, 6, 8, 10);stream.skip(3).forEach(System.out::println);}
}
7.截断(limit)
截断是截取 n 个元素的操作。该操作使用 Stream 接口提供的【Stream limit(long maxSize)】方法实现。
跳过操作和截断操作可以联合使用。
public class SkipTest {public static void main(String[] args) {Stream<Integer> stream = Stream.of(1, 3, 5, 7, 9, 2, 4, 6, 8, 10);stream.limit(3).forEach(System.out::println);}
}
五、终止操作
触发终止操作时才会真正执行中间操作,终止操作执行完毕会返回计算结果。终止操作执行完毕 Stream 就会失效,即不能再执行中间操作或终止操作了。
1.遍历(forEach)
使用 Stream 接口提供的【void forEach(Consumer<? super T> action)】方法来遍历计算结果。
2.匹配(match)
- 判断 Stream 中是否存在某些元素;
- 方法:
- allMatch(Predicate<? super T> predicate):检查是否匹配所有元素;
- anyMatch(Predicate<? super T> predicate):检查是否匹配至少一个元素;
- noneMatch(Predicate<? super T> predicate):检查是否一个元素都不匹配;
- Optional findFirst:获得第一个元素。Optional是一个值的容器,可以通过 get() 获取容器的值。
public class MatchTest {public static void main(String[] args) {Student s1 = new Student("炘南", 23);Student s2 = new Student("东杉", 27);Student s3 = new Student("北淼", 25);Student s4 = new Student("坤中", 18);Student s5 = new Student("西钊", 24);Stream<Student> stream = Stream.of(s1, s2, s3, s4, s5);// 判断全部元素年龄大于18岁
// boolean allMatch = stream.allMatch(s -> s.getAge() > 18);
// System.out.println(allMatch); // false// 判断是否有元素年龄大于18岁
// boolean anyMatch = stream.anyMatch(s -> s.getAge() > 18);
// System.out.println(anyMatch); // true// 判断是否有元素年龄小于18岁
// boolean noneMatch = stream.noneMatch(s -> s.getAge() > 18);
// System.out.println(noneMatch); // false// 判断第一个元素年龄大于18岁boolean isMatch = stream.findFirst().get().getAge() > 18;System.out.println(isMatch); // true}
}
3.归约(reduce)
- 将所有元素按照指定规则合并成一个结果;
- 方法:
- reduce(BinaryOperator<T> accumulator);
- reduce(T identity, BinaryOperator<T> accumulator)。
- reduce 操作可以实现从一组元素中生成一个值,而 max()、min()、count() 方法都属于 reduce 操作,因为常用所以单独设为方法。
public class ReduceTest {public static void main(String[] args) {/** 求和* */int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};IntStream stream = Arrays.stream(arr);OptionalInt reduce = stream.reduce((a, b) -> a + b);System.out.println(reduce.getAsInt()); // 55/** 比较字符串长度,并将最长的字符串输出* */String[] arr2 = {"hello", "world", "java", "stream", "test"};Stream<String> stream1 = Arrays.stream(arr2);String s = stream1.reduce((a, b) -> a.length() > b.length() ? a : b).get();System.out.println(s); // stream/** 获得学生的总年龄* */Student s1 = new Student("老张", 18);Student s2 = new Student("老李", 22);Student s3 = new Student("老王", 19);Student s4 = new Student("老郭", 31);ArrayList<Student> students = new ArrayList<>();students.add(s1);students.add(s2);students.add(s3);students.add(s4);Stream<Student> stream2 = students.stream();Integer sumAge = stream2.map(Student::getAge).reduce((a, b) -> a + b).get();System.out.println(sumAge); // 90/** count()* */Stream<String> stream3 = Stream.of("hello", "world", "java", "stream", "test");long count = stream3.count();System.out.println(count); // 5/** max()* */Stream<Integer> stream4 = Stream.of(1, 14, 5, 38, 62, 4);Optional<Integer> max = stream4.max(Integer::compareTo);System.out.println(max.get()); // 62/** min()* */Stream<Integer> stream5 = Stream.of(1, 14, 5, 38, 62, 4);Optional<Integer> min = stream5.min(Integer::compareTo);System.out.println(min.get()); // 1}
}
4.收集(collect)
把一个流收集起来,最终可以是一个值也可以是一个新的集合。调用 Stream 接口提供的【collect(Collector<? super T, A, R collector)】方法实现,参数中的 Collector 对象大都是直接通过 Collectors 工具类获得,实际上传入的 Collector 决定了 collect() 的行为。
(1)归集(toList / toSet / toMap)
因为 Stream 流不存储数据,那么在 Stream 流中数据处理完成后,若需要把数据存入集合中,就需要使用归集操作。
Collectors 提供了 toList、toSet、toMap 操作,此时并没有明确存储数据对应的集合具体类型, 若需要明确具体类型,需要使用toCollection 来实现。
public class CollectTo {public static void main(String[] args) {/** toList():将流中的元素收集到一个List集合中* */Student s1 = new Student("孙悟空", 18);Student s2 = new Student("猪八戒", 2);Student s3 = new Student("唐僧", 45);Stream<Student> stream1 = Stream.of(s1, s2, s3);List<Student> collect1 = stream1.collect(Collectors.toList());System.out.println(collect1);/** toSet():将流中的元素收集到一个Set集合中* */Stream<Integer> stream2 = Stream.of(1, 3, 5, 7, 9);Set<Integer> collect2 = stream2.collect(Collectors.toSet());System.out.println(collect2);/** toMap():将流中的元素收集到一个Map集合中* */Stream<String> stream3 = Stream.of("1:I ", "2:Love ", "3:You ");Map<String, String> collect3 = stream3.collect(Collectors.toMap(new Function<String, String>() {@Overridepublic String apply(String s) {return s.substring(0, s.indexOf(":"));}}, new Function<String, String>() {@Overridepublic String apply(String s) {return s.substring(s.indexOf(":") + 1);}}));collect3.forEach((k, v) -> System.out.println(k + ":" + v));/** toCollection()* */Stream<Double> stream4 = Stream.of(3.14, 5.20, 13.14);HashSet<Double> collect4 = stream4.collect(Collectors.toCollection(HashSet::new));System.out.println(collect4);}
}
(2)统计(counting / averaging)
- 计数:counting;
- 平均值:averagingInt、averagingLong、averagingDouble;
- 最值:maxBy、minBy;
- 求和:summingInt、summingLong、summingDouble;
- 统计以上所有:summarizingInt、summarizingLong、summarizingDouble。
public class CollectCouAve {public static void main(String[] args) {/** counting* */Student s1 = new Student("光光", 18);Student s2 = new Student("冬冬", 2);Student s3 = new Student("球球", 16);Student s4 = new Student("红红", 23);Student s5 = new Student("白白", 45);Student[] students = {s1, s2, s3, s4, s5};Stream<Student> stream1 = Arrays.stream(students);Long collect1 = stream1.collect(Collectors.counting());System.out.println(collect1); // 5/** averagingInt* */Stream<Student> stream2 = Arrays.stream(students);Double collect2 = stream2.collect(Collectors.averagingInt(Student::getAge));System.out.println(collect2); // 20.8/** maxBy* */Stream<Student> stream3 = Arrays.stream(students);Optional<Student> collect3 = stream3.collect(Collectors.maxBy((o1, o2) -> o1.getAge() - o2.getAge()));System.out.println(collect3.get()); // Student{name='白白', age=45}/** summingInt* */Stream<Student> stream4 = Arrays.stream(students);Integer collect4 = stream4.collect(Collectors.summingInt(Student::getAge));System.out.println(collect4); // 104/** summarizingInt* */Stream<Student> stream5 = Arrays.stream(students);IntSummaryStatistics collect5 = stream5.collect(Collectors.summarizingInt(Student::getAge));System.out.println(collect5); // IntSummaryStatistics{count=5, sum=104, min=2, average=20.800000, max=45}}
}
(3)分组(groupingBy)
将 Stream 按条件分为若干个 Map。
public class GroupingByTest {public static void main(String[] args) {Student s1 = new Student("宋江", 18);Student s2 = new Student("卢俊义", 18);Student s3 = new Student("吴用", 23);Student s4 = new Student("公孙胜", 23);Student s5 = new Student("关胜", 45);Student[] students = {s1, s2, s3, s4, s5};Stream<Student> stream = Arrays.stream(students);Map<Integer, List<Student>> collect = stream.collect(Collectors.groupingBy(Student::getAge));collect.forEach((k, v) -> System.out.println(k + ":" + v));}
}
(4)接合(joining)
将 Stream 计算的数据按照一定规则进行拼接。
public class JoiningTest {public static void main(String[] args) {Student s1 = new Student("州洲", 18);Student s2 = new Student("冬冬", 2);Student s3 = new Student("由由", 16);Student s4 = new Student("辉辉", 23);Student s5 = new Student("季季", 45);Student[] students = {s1, s2, s3, s4, s5};Stream<Student> stream = Arrays.stream(students);Stream<String> stream1 = stream.map(Student::getName);String collect = stream1.collect(Collectors.joining(","));System.out.println(collect); // 州洲,冬冬,由由,辉辉,季季}
}