ArrayList<Integer> list = new ArrayList<>();
list.add(2);
list.add(10);
list.add(10);
list.add(3);
list.add(5);
list.stream().filter(a -> a % 2 == 0).forEach(a -> System.out.println(a));
以上代码就是获得集合数据中的偶数。
和工厂流水线工作差不多。
Stream可以通过结合Lambda表达式,简化集合、数组的操作。
主要步骤
那么如何使用一个Stream流呢?
获取方式 | 方法名 | 说明 |
---|---|---|
单列集合 | default Stream stream() | Collection中的默认方法 |
双列集合 | 无,可以通过调用集合方法变为单列集合。 | 无法直接使用stream流 |
数组 | public static Stream stream(T[] array) | Arrays工具类中的静态方法 |
零散的数据 | public static Stream of(T… values) | Stream接口中的静态方法 |
//1.单列集合获取Stream流
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "a", "b", "c", "d", "e", "f", "g");
// 获取到一条流水线,并把集合中的数据放到流水线。
Stream<String> stream1 = list.stream();
//使用终结方法打印一下流水线上的数据
stream1.forEach(System.out::println);
//双列集合
// 创建双列集合
HashMap<String, Integer> mp = new HashMap<>();
mp.put("张三", 12);
mp.put("里斯", 29);
// 第一种获取Stream流的方法
mp.keySet().stream().forEach(System.out::println);
System.out.println("-----------------------");
// 第二种获取Stream流的方法
mp.entrySet().stream().forEach(System.out::println);
//数组获取Stream流
Integer[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
Stream<Integer> stream1 = Arrays.stream(arr);
stream1.filter(a -> a % 2 == 0).forEach(System.out::println);
//一堆零散的数据,引用类型以及基本类型都可以
Stream<Integer> integerStream = Stream.of(1, 2, 3, 3, 4, 5);
integerStream.filter(a -> a > 3).forEach(System.out::println);
细节
stream接口中的静态方法of,方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组。
但是数组必须引用数据类型的,如果传递基本数据类型,会把整个数组当作一个元素,放在stream中。
方法名 | 说明 |
---|---|
Stream filter(Predicate super T> predicate) | 过滤 |
Stream limit(long maxSize) | 获取前几个元素 |
Stream skip(long n) | 跳过前几个元素 |
Stream distinct() | 元素去重,依赖(hascode和equals方法) |
static Stream concat(Stream a, Stream b) | 合并a和b两个流为一个流,尽可能数据类型一致 |
Stream map(Function |
转换流中的数据类型 |
注意1:中间方法,返回新的Stream流,原来的流只能使用一次,可以使用链式编程
注意2:修改Stream流中的数据,不会影响原来集合或者数组中的数据
以map函数为例:
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张三-12", "李四-35", "赵武-56");
Stream<String> stream1 = list.stream();
stream1.map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
String[] arr = s.split("-");
return Integer.parseInt(arr[1]);
}
}).forEach(System.out::println);
结果为:
12
35
56
方法名 | 说明 |
---|---|
void forEach(Consumer action) | 遍历 |
long count() | 统计 |
toArray() | 收集流中的数据,放到数组中 |
collect(Collector collector) | 收集流中的数据,放到集合中 |
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张三-12", "李四-35", "赵武-56");
Stream<String> stream1 = list.stream();
//返回值,如果无参数,那返回Object数组
//如果有参数,参数作用是负责创建一个指定类型的数组,
//底层会依次得到流里面的每一个数据,并把数据放到数组当中
String[] res = stream1.toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
return new String[value];
}
});
System.out.println(Arrays.toString(res));
collect详细解释
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张三-12", "李四-35", "赵武-56");
Stream<String> stream1 = list.stream();
//把年龄大于30的收集起来,先进行过滤,然后进行收集,调用Collectors.toList()
List<String> new_list = stream1.filter(s -> Integer.parseInt(s.split("-")[1]) > 30).collect(Collectors.toList());
System.out.println(new_list);
收集到list
中,使用Collectors.toList()
收集到Set
,使用Collectors.toSet()
,与list
相比,set
会去除重复元素。
收集到map
,使用 Collectors.toMap ()
, 注意:键值不能重复
Map<String, Integer> mp = stream1.collect(Collectors.toMap(new Function<String, String>() {//键值规则
@Override
public String apply(String s) {
return s.split("-")[0];
}
}, new Function<String, Integer>() {//值的生成规则
@Override
public Integer apply(String s) {
return Integer.parseInt(s.split("-")[1]);
}
}));
等价于用lambda表达式(只有函数式接口才能进行lambda简化)
Map<String, Integer> mp = stream1.collect(Collectors.toMap(s -> s.split("-")[0], s -> Integer.parseInt(s.split("-")[1])));
package com.demo;
import java.math.BigInteger;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Test {
public static void main(String[] args) {
ArrayList<String> boy = new ArrayList<>();
ArrayList<String> girl = new ArrayList<>();
Collections.addAll(boy, "李一封,35", "菜许坤,31", "五一饭,27", "罗想,37");
Collections.addAll(girl, "杨米,18", "杨樱花,28", "刘一飞,18", "高元元,18");
Stream<String> stream = Stream.concat(boy.stream().filter(s -> s.split(",")[0].length() == 3).limit(2),
girl.stream().filter(s -> s.startsWith("杨")));
List<Actor> actors = stream.map(s -> new Actor(s.split(",")[0], Integer.parseInt(s.split(",")[1])))
.collect(Collectors.toList());
for (Actor actor : actors) {
System.out.println("name:" + actor.getName() + " age:" + actor.getAge());
}
}
}
class Actor{
private String name;
private int age;
public Actor(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;
}
}
把已经存在的方法当做函数式接口中抽象方法的方法体。
函数式接口是只有一个抽象方法的接口
Arrays.sort(arr, class_name::subcmp);
public static int subcmp(int n1, int n2) {
return n2 - n1;
}
格式:类名::静态方法
范例:Integer::parseInt
//"1", "2", "3", "4" 变成整型
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "1", "2", "3", "4" 变成整型);
list.stream().map(Integer::parseInt).forEach(System.out::println);
格式:对象::成员方法
本类以及父类在非静态方法中调用
格式:类名::new
范例:Student::new
为了创建对象。
ArrayList<String> boy = new ArrayList<>();
ArrayList<String> girl = new ArrayList<>();
Collections.addAll(boy, "李一封,35", "菜许坤,31", "五一饭,27", "罗想,37");
Collections.addAll(girl, "杨米,18", "杨樱花,28", "刘一飞,18", "高元元,18");
Stream<String> stream = Stream.concat(boy.stream().filter(s -> s.split(",")[0].length() == 3).limit(2),
girl.stream().filter(s -> s.startsWith("杨")));
List<Actor> actors = stream.map(Actor::new)))
.collect(Collectors.toList());
for (Actor actor : actors) {
System.out.println("name:" + actor.getName() + " age:" + actor.getAge());
}
class Actor{
private String name;
private int age;
public Actor(String name, int age) {
this.name = name;
this.age = age;
}
public Actor(String s) { //新加的
this.name = s.split(",")[0];
this.age = Integer.parseInt(s.split(",")[1]));
}
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;
}
}
类名引用成员方法
格式:类名::成员方法
范例:String::substring
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "aaaa", "bbb", "ccc");
list.stream().map(String::toUpperCase).forEach(System.out::println);
规则:
抽象方法形参的详解:
第一个参数:表示被引用方法的调用者,决定了可以引用哪些类中的方法。在Stream流中,第一个参数一般都表示流里面的每一个数据。
引用数组的构造方法
格式:数据类型[]::new
范例:int[]::new
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3);
Integer[] arr = list.stream().toArray(Integer[]::new);
数组的类型要和流中的数据类型保持一致。
创建集合添加学生对象,name,age
获取姓名并放到数组中
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class Func {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张三,18", "李四,20", "王五,21");
String[] name = list.stream().map(Student::new).map(Student::getName).toArray(String[]::new);
System.out.println(Arrays.toString(name));
}
}
class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student(String str) {
this.name = str.split(",")[0];
this.age = Integer.parseInt(str.split(",")[1]);
}
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;
}
}