什么是Stream
Stream是对集合对象的增强,专注于对集合对象进行各种便利的操作.
Stream相关的接口与方法
-
java.util.stream包下新增Stream类
-
Collection接口中新增stream()和parallelStream()默认方法
-
Arrays类中新增stream(T array)方法
使用流程
当我们使用一个流的时候,通常包括三个基本步骤:
获取一个数据源(source)→ 中间操作(数据转换)→终止操作(数据收集)。
代码
Stream操作中使用了lambda表达式,lambda表达式入门到实践
@Test
public void streamTest() {
//需求:打印出集合中长度大于2的元素
//创建集合
List<String> list= Arrays.asList("AAA","B","CC","DDDD");
//2.使用遍历方式打印
for (String s: list) {
if (s.length()>2){
System.out.println(s);
}
}
System.out.println("***************************");
//3.使用Stream的方式
//获取Stream流
//进行中间操作(过滤)
//进行终止操作(for循环打印)
list.stream().filter(s -> s.length()>2).forEach(System.out::println);
}
Stream获取
- Collection.stream(): 集合对象获取串行流
- Collection.parallelStream(): 集合对象获取并行流
- Arrays.stream(T array): Arrays工具类方法获取
- Stream.of(T… values)/Stream.of(T t): Stream静态方法获取
需要注意的是,对于基本数值型,目前有三种对应的包装类型 Stream:
IntStream、LongStream、DoubleStream。
代码
@Test
public void createStream() {
//1.通过Collection.stream()方法创建Stream流
//首先获取集合实列
List<String> list= Arrays.asList("A","B","C","D");
//获取Stream流
Stream<String> stream = list.stream();
//2.通过Collection.parallelStream()方法创建Stream流
//获取Stream流
Stream<String> parallelStream = list.parallelStream();
//3.Arrays.stream(T array)方式获取
//首先获取数组
//注意:IntStream与Stream同为BaseStream的子类
int[] array={1,2,3,4};
IntStream intStream = Arrays.stream(array);
//4.Stream.of(T... values)/Stream.of(T t)方式获取
Stream<String> stringStream = Stream.of("A", "B", "C");
}
Stream常见中间操作
- filter: 从流中过滤某些元素
- distinct: 筛选,通过流所生成元素的hashCode()和equals()去除重复元素。
- sorted : 排序
- limit: 设置流中元素数量的上限
- skip: 跳过元素
- map: 将元素转换成其他形式或提取信息。
代码
数据创建
public class User {
//姓名
private String name;
//性别
private String sex;
//年龄
private Integer age;
public User(String name, String sex, Integer age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(name, user.name) &&
Objects.equals(sex, user.sex) &&
Objects.equals(age, user.age);
}
@Override
public int hashCode() {
return Objects.hash(name, sex, age);
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
}
public class DataUtils {
/**
* 获取User集合
*
* @return
*/
public static List<User> getUserList() {
List<User> list = new ArrayList<>();
User user1 = new User("张小凡", "男", 25);
User user2 = new User("陆雪琪", "女", 26);
User user3 = new User("碧瑶", "女", 24);
User user4 = new User("兽神", "男", 1000);
User user5 = new User("小白", "女", 500);
User user6 = new User("田不易", "男", 100);
User user7 = new User("林惊羽", "男", 25);
User user8 = new User("张小凡", "男", 25);
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
list.add(user5);
list.add(user6);
list.add(user7);
list.add(user8);
return list;
}
}
- filter
@Test
public void filterTest(){
//需求:打印出全部男性角色
List<User> list = DataUtils.getUserList();
//获取stream流
//使用filter方法进行过滤,传入lambda表达式
//使用forEach打印
list.stream().filter(value-> value.getSex().equals("男")).forEach(System.out::println);
}
- distinct
@Test
public void distinctTest(){
//需求:打印出全部男性角色
List<User> list = DataUtils.getUserList();
//获取stream流
//使用distinct去掉重复元素,已经重写了hashCode()和equals()方法
//使用forEach打印
list.stream().distinct().forEach(System.out::println);
}
- sorted
@Test
public void sortedTest() {
//需求:按年龄从大到小进行排序
List<User> list = DataUtils.getUserList();
//可以实现Comparable接口也可使用Comparator接口,这里以Comparator方式举例
//Comparator.comparingInt(User::getAge) 对age条件进行排序
//reversed()方法是反序
list.stream().sorted(Comparator.comparingInt(User::getAge).reversed()).forEach(System.out::println);
}
- limit
@Test
public void limitTest() {
//需求:打印年龄最小的两个元素
List<User> list = DataUtils.getUserList();
//可以实现Comparable接口也可使用Comparator接口,这里以Comparator方式举例
//Comparator.comparingInt(User::getAge) 对age条件进行排序
//reversed()方法是反序
//limit 设置最大数量
list.stream().sorted(Comparator.comparingInt(User::getAge)).limit(2).forEach(System.out::println);
}
- skip
@Test
public void skipTest() {
//需求:从第二个元素开始全部遍历
List<User> list = DataUtils.getUserList();
list.stream().skip(1).forEach(System.out::println);
}
- map
@Test
public void mapTest() {
//需求:获取name的集合
List<User> list = DataUtils.getUserList();
//获取stream流
//去掉重复元素
//获取元素中的名称
//数据收集
List<String> stringList = list.stream().distinct().map(User::getName).collect(Collectors.toList());
System.out.println(stringList);
}
Stream终止操作
- forEach: 遍历操作
- allMatch: 检查是否匹配所有元素
- anyMatch: 检查是否至少匹配一个元素
- noneMatch: 检查是否没有匹配所有元素
- findFirst: 返回第一个元素
- findAny: 返回当前流中的任意元素
- count: 返回流中元素的总个数
- max: 返回流中最大值
- min: 返回流中最小值
- reduce: 归约操作
- collect : 收集,将流转行成想要的结果
代码
Stream终止操作,Stream如果不调用终止操作的方法,中间操作不会执行,执行完一次终止操作之后,流不能继续使用
- match
@Test
public void matchTest() {
//需求:判断年龄是否都大于18岁
List<User> list = DataUtils.getUserList();
//获取stream流
//进行匹配操作
boolean allMatch = list.stream().allMatch(user -> user.getAge() >= 18);
System.out.println(allMatch);
//anyMatch与noneMatch操作类似
}
@Test
public void reduceTest() {
//需求:求集合中元素总年龄
List<User> list = DataUtils.getUserList();
//获取stream流
//将User转成Integer
//进行求和
Integer sum = list.stream().map(User::getAge).reduce(0, Integer::sum);
System.out.println(sum);
}
collect
常用的Collectors.toList()/Collectors.toSet()
@Test
public void collectTest() {
//需求:将获取年龄的集合从小到大排列
List<User> list = DataUtils.getUserList();
//获取stream流
//将User转成Integer
//进行排序
//数据搜集
List<Integer> integers = list.stream().map(User::getAge).distinct().sorted().collect(Collectors.toList());
System.out.println(integers);
}
总结
- Stream不是数据结构,而是对集合的操作API
- Stream用到lambda表达式
- Stream不存储数据,只从数据源中读取数据
- Stream操作不改变原集合,产生新的数据
- Stream流可以进行多次中间操作,不执行终止操作时,中间操作不会执行.执行一次终止操作后,流就不可用
- Stream支持并行化,并不需要自己编写多线程代码