Stream流(JDK8新特性)
Stream流(也叫Stream API)。它是从JDK8以后才有的一个新特性,是专业用于对集合或者数组进行便捷操作的。
Stream流体验
案例需求:有一个List集合,元素有"张三丰","张无忌","周芷若","赵敏","张强"
,找出姓张,且是3个字的名字,存入到一个新集合中去。
1 2 3
| List<String> names = new ArrayList<>(); Collections.addAll(names, "张三丰","张无忌","周芷若","赵敏","张强"); System.out.println(names);
|
1 2 3 4 5 6 7 8
| List<String> list = new ArrayList<>(); for (String name : names) { if(name.startsWith("张") && name.length() == 3){ list.add(name); } } System.out.println(list);
|
- 用Stream流来做,代码是这样的(ps: 是不是想流水线一样,一句话就写完了)
1 2
| List<String> list2 = names.stream().filter(s -> s.startsWith("张")).filter(a -> a.length()==3).collect(Collectors.toList()); System.out.println(list2);
|
先不用知道这里面每一句话是什么意思,具体每一句话的含义,待会再一步步学习。现在只是体验一下。
学习Stream流我们接下来,会按照下面的步骤来学习。
Stream流的创建
主要掌握下面四点:
- 如何获取List集合的Stream流?
- 如何获取Set集合的Stream流?
- 如何获取Map集合的Stream流?
- 如何获取数组的Stream流?
直接上代码演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
|
public class StreamTest2 { public static void main(String[] args) { List<String> names = new ArrayList<>(); Collections.addAll(names, "张三丰","张无忌","周芷若","赵敏","张强"); Stream<String> stream = names.stream();
Set<String> set = new HashSet<>(); Collections.addAll(set, "刘德华","张曼玉","蜘蛛精","马德","德玛西亚"); Stream<String> stream1 = set.stream(); stream1.filter(s -> s.contains("德")).forEach(s -> System.out.println(s));
Map<String, Double> map = new HashMap<>(); map.put("古力娜扎", 172.3); map.put("迪丽热巴", 168.3); map.put("马尔扎哈", 166.3); map.put("卡尔扎巴", 168.3);
Set<String> keys = map.keySet(); Stream<String> ks = keys.stream();
Collection<Double> values = map.values(); Stream<Double> vs = values.stream();
Set<Map.Entry<String, Double>> entries = map.entrySet(); Stream<Map.Entry<String, Double>> kvs = entries.stream(); kvs.filter(e -> e.getKey().contains("巴")) .forEach(e -> System.out.println(e.getKey()+ "-->" + e.getValue()));
String[] names2 = {"张翠山", "东方不败", "唐大山", "独孤求败"}; Stream<String> s1 = Arrays.stream(names2); Stream<String> s2 = Stream.of(names2); } }
|
Stream流中间方法
我们学习了创建Stream流的方法。接下来我们再来学习,Stream流中间操作的方法。
中间方法指的是:调用完方法之后其结果是一个新的Stream流,于是可以继续调用方法,这样一来就可以支持链式编程(或者叫流式编程)。
Stream提供的常用中间方法 |
说明 |
Stream<T> filter(Predicate<? super T> predicate) |
用于对流中的数据进行过滤 |
Stream<T> sorted() |
对元素进行升序排序 |
Stream<T> sorted(Comparator<? super T> comparator) |
按照指定规则排序 |
Stream<T> limit(long maxSize) |
获取前几个元素 |
Stream<T> skip(long n) |
跳过前几个元素 |
Stream<T> distinct() |
去除流中重复的元素 |
<R> Stream<R> map(Function<? super T,? extends R> mapper) |
对元素进行加工,并返回对应的新流 |
static <T> Stream<T> concat(Stream a,Stream b) |
合并a和b两个流为一个流 |
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
|
public class StreamTest3 { public static void main(String[] args) { List<Double> scores = new ArrayList<>(); Collections.addAll(scores, 88.5, 100.0, 60.0, 99.0, 9.5, 99.6, 25.0); scores.stream().filter(s -> s >= 60).sorted().forEach(s -> System.out.println(s));
List<Student> students = new ArrayList<>(); Student s1 = new Student("蜘蛛精", 26, 172.5); Student s2 = new Student("蜘蛛精", 26, 172.5); Student s3 = new Student("紫霞", 23, 167.6); Student s4 = new Student("白晶晶", 25, 169.0); Student s5 = new Student("牛魔王", 35, 183.3); Student s6 = new Student("牛夫人", 34, 168.5); Collections.addAll(students, s1, s2, s3, s4, s5, s6); students.stream().filter(s -> s.getAge() >= 23 && s.getAge() <= 30) .sorted((o1, o2) -> o2.getAge() - o1.getAge()) .forEach(s -> System.out.println(s));
students.stream().sorted((o1, o2) -> Double.compare(o2.getHeight(), o1.getHeight())) .limit(3).forEach(System.out::println); System.out.println("-----------------------------------------------");
students.stream().sorted((o1, o2) -> Double.compare(o2.getHeight(), o1.getHeight())) .skip(students.size() - 2).forEach(System.out::println);
students.stream().filter(s -> s.getHeight() > 168).map(Student::getName) .distinct().forEach(System.out::println);
students.stream().filter(s -> s.getHeight() > 168) .distinct().forEach(System.out::println);
Stream<String> st1 = Stream.of("张三", "李四"); Stream<String> st2 = Stream.of("张三2", "李四2", "王五"); Stream<String> allSt = Stream.concat(st1, st2); allSt.forEach(System.out::println); } }
|
Stream流终结方法
最后,我们再学习Stream流的终结方法。这些方法的特点是,调用完方法之后,其结果就不再是Stream流了,所以不支持链式编程。
Stream提供的常用终结方法 |
说明 |
void forEach(Consumer action) |
对此流运算后的元素执行遍历 |
long count() |
统计此流运算后的元素个数 |
OptionalkT> max(Comparator<? super T> comparator) |
获取此流运算后的最大值元素 |
Optional<T> min(Comparator<? super T> comparator) |
获取此流运算后的最小值元素 |
话不多说,直接上代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
public class StreamTest4 { public static void main(String[] args) { List<Student> students = new ArrayList<>(); Student s1 = new Student("蜘蛛精", 26, 172.5); Student s2 = new Student("蜘蛛精", 26, 172.5); Student s3 = new Student("紫霞", 23, 167.6); Student s4 = new Student("白晶晶", 25, 169.0); Student s5 = new Student("牛魔王", 35, 183.3); Student s6 = new Student("牛夫人", 34, 168.5); Collections.addAll(students, s1, s2, s3, s4, s5, s6); long size = students.stream().filter(s -> s.getHeight() > 168).count(); System.out.println(size);
Student s = students.stream().max((o1, o2) -> Double.compare(o1.getHeight(), o2.getHeight())).get(); System.out.println(s);
Student ss = students.stream().min((o1, o2) -> Double.compare(o1.getHeight(), o2.getHeight())).get(); System.out.println(ss); } }
|
收集Stream流
就是把Stream流操作后的结果转回到集合或者数组中去返回
stream流:方便操作集合/数组的手段
集合/数组:才是开发中的目的
Stream提供的常用终结方法 |
说明 |
R collect(Collector collector) |
把流处理后的结果收集到一个指定的集合中去 |
Object[] toArray() |
把流处理后的结果收集到一个数组中去 |
代码示例走起:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
public class StreamTest4 { public static void main(String[] args) { List<Student> students = new ArrayList<>(); Student s1 = new Student("蜘蛛精", 26, 172.5); Student s2 = new Student("蜘蛛精", 26, 172.5); Student s3 = new Student("紫霞", 23, 167.6); Student s4 = new Student("白晶晶", 25, 169.0); Student s5 = new Student("牛魔王", 35, 183.3); Student s6 = new Student("牛夫人", 34, 168.5); Collections.addAll(students, s1, s2, s3, s4, s5, s6); List<Student> students1 = students.stream().filter(a -> a.getHeight() > 170).collect(Collectors.toList()); System.out.println(students1);
Set<Student> students2 = students.stream().filter(a -> a.getHeight() > 170).collect(Collectors.toSet()); System.out.println(students2);
Map<String, Double> map = students.stream().filter(a -> a.getHeight() > 170) .distinct().collect(Collectors.toMap(a -> a.getName(), a -> a.getHeight())); System.out.println(map);
Student[] arr = students.stream().filter(a -> a.getHeight() > 170).toArray(len -> new Student[len]); System.out.println(Arrays.toString(arr)); } }
|
简述单列集合、双列集合、数组分别如何获取Stream流对象,并进行演示:
java.util.Collection
接口中加入了default方法stream()获取流对象,因此其所有实现类均可通过此方式获取流。
java.util.Map
接口想要获取流,先通过keySet()
、values()
或entrySet()
方法获取键、值或键值对的单列集合,再通过stream()获取流对象。
- 数组获取流,使用Stream接口中的的静态方法
of(T...values)
获取流。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public static void main(String[] args) { List<String> list = new ArrayList<>(); Stream<String> stream1 = list.stream();
Set<String> set = new HashSet<>(); Stream<String> stream2 = set.stream();
Map<String, String> map = new HashMap<>(); Stream<String> keyStream = map.keySet().stream(); Stream<String> valueStream = map.values().stream(); Stream<Map.Entry<String,String>> entryStream = map.entrySet().stream();
String[] array = {"东邪", "西毒", "南帝", "北丐", "中神通"}; Stream<String> stream = Stream.of(array); Stream<String> streamA = Stream.of("郭靖", "杨康"); Stream<String> streamB = Stream.of("黄蓉", "穆念慈"); List<String> strList = Stream.concat(streamA, streamB).collect(Collectors.toList()); }
|
到这里,关于Stream流的操常见操作我们就已经学习完了。
链接
封面图来源:https://www.pixiv.net/artworks/101462757