Java8的两个重大改变,一个是Lambda表达式,另一个就是Stream API表达式。Stream 是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找、过滤、筛选等操作。
1为什么使用stream流
当我们需要对集合中的元素进行操作的时候,除了必需的添加、删除、获取外,最典型的就是集合遍历。我们来体验 集合操作数据的弊端,需求如下:
当我们需要对集合中的元素进行操作的时候,除了必需的添加、删除、获取外,最典型的就是集合遍历。我们来体验 集合操作数据的弊端,需求如下:
public class Test {
public static void main(String[] args) {
// 一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,成俊杰,张三丰
// 需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据
List<String> list=new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("程俊杰");
list.add("张三丰");
//1.拿到所有姓张的
List<String> newList01=new ArrayList<>();
for(String n:list){
if(n.startsWith("张")){
newList01.add(n);
}
}
//2.拿到名字长度为3个字的
List<String> newList02=new ArrayList<>();
for(String n:newList01){
if(n.length()==3){
newList02.add(n);
}
}
//3.打印这些数据
for(String s:newList02){
System.out.println(s);
}
}
}
分析:
循环遍历的弊端
这段代码中含有三个循环,每一个作用不同:
首先筛选所有姓张的人;
然后筛选名字有三个字的人;
最后进行对结果进行打印输出。
每当我们需要对集合中的元素进行操作的时候,总是需要进行循环、循环、再循环。这是理所当然的么?不是。循环 是做事情的方式,而不是目的。每个需求都要循环一次,还要搞一个新集合来装数据,如果希望再次遍历,只能再使 用另一个循环从头开始。
Stream初体验
public class Test2 {
public static void main(String[] args) {
List<String> list=new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("程俊杰");
list.add("张三丰");
//list.stream().filter(t->t.startsWith("张")).filter(t->t.length() == 3).forEach(item-> System.out.println(item));
list.stream().filter(t->t.startsWith("张")).filter(t->t.length() == 3).forEach(System.out::println);
}
}
2.Stream流的原理
Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工 处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。

3.步骤
(1)获取Stream流对象
(2) 中间操作---返回类型还是Stream流对象。
(3)终止操作---不在是Stream流对象

4.获取Stream流对象的方式
(1) 通过集合对象调用stream()
(2)通过Arrays获取stream流对象
(3)通过Stream流里面of方
public class Test3 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周世荣");
list.add("赵敏");
//第一种:通过集合对象调用stream()
Stream<String> stream = list.stream();
stream.forEach(System.out::println);
//第二种:使用Arrays工具类
String [] arr={};
Stream<String> stream1 = Arrays.stream(arr);
stream1.forEach(System.out::println);
//第三种:Stream类
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
integerStream.forEach(System.out::println);
//上边的流都是串行流,并行流
Stream<String> stringStream = list.parallelStream();
stringStream.forEach(System.out::println);
}
}
5.Stream流的api方法
举个简单的例子:
假设有一个Person类和一个Person列表,现在有两个需求:1)找到年龄大于18岁的人并输出;2)找出所有中国人的数量
public class Test03 {
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪", 18, "中国", 'F'));
personList.add(new Person("Tom", 24, "美国", 'M'));
personList.add(new Person("Harley", 22, "英国", 'F'));
personList.add(new Person("向天笑", 20, "中国", 'M'));
personList.add(new Person("李康", 22, "中国", 'M'));
personList.add(new Person("小梅", 20, "中国", 'F'));
personList.add(new Person("何雪", 21, "中国", 'F'));
personList.add(new Person("李康", 22, "中国", 'M'));
//1. 年龄大于18 filter:过滤掉不满足条件的元素. forEach:输出元素. ---如果没有终止函数,那么中间函数的代码不会被执行。
personList.stream().filter(t -> t.getAge() > 18).forEach(System.out::println);
//2. 找出中国人 并统计个数: count()
long count = personList.stream().filter(t -> t.getCountry().equals("中国")).count();
System.out.println("中国"+count+"个");
}
}
class Person {
private String name;
private Integer age;
private String country;
private char sex;
public Person() {
}
public Person(String name, Integer age, String country, char sex) {
this.name = name;
this.age = age;
this.country = country;
this.sex = sex;
}
/**
* 获取
*
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
*
* @return age
*/
public Integer getAge() {
return age;
}
/**
* 设置
*
* @param age
*/
public void setAge(Integer age) {
this.age = age;
}
/**
* 获取
*
* @return country
*/
public String getCountry() {
return country;
}
/**
* 设置
*
* @param country
*/
public void setCountry(String country) {
this.country = country;
}
/**
* 获取
*
* @return sex
*/
public char getSex() {
return sex;
}
/**
* 设置
*
* @param sex
*/
public void setSex(char sex) {
this.sex = sex;
}
public String toString() {
return "Person{name = " + name + ", age = " + age + ", country = " + country + ", sex = " + sex + "}";
}
}
(2)找出年龄最大和最小
//3.找出年龄最大的人
Person person1 = personList.stream().max((o1, o2) -> o1.getAge() - o2.getAge()).get();
System.out.println(person1);
//4.找出年龄最小的人
Person person2 = personList.stream().min((o1, o2) -> o1.getAge() - o2.getAge()).get();
System.out.println(person2);
(3)map->会把集合中的元素转化成另一种类型

personList.stream().filter(t->t.getCountry().equals("中国")).map(t->new P(t.getName(),t.getAge())).forEach(System.out::println);
案例一:英文字符串数组的元素全部改为大写。整数数组每个元素+3
public class Test04 {
public static void main(String[] args) {
//字符串大写
List<String> list = Arrays.asList("hello", "world", "java", "spring", "springmvc");
list.stream().map(String::toUpperCase).forEach(System.out::println);
//整数数组每个元素+3
List<Integer> list2 = Arrays.asList(1, 3, 15, 23, 29);
list2.stream().map(item->item+3).forEach(System.out::println);
}
}
(4)收集 collect
把处理过的集合搜集成新的集合。
List<Person> personList = new ArrayList<>();
personList.add(new Person("小梅",24,"中国",'F'));
personList.add(new Person("欧阳雪",18,"中国",'F'));
personList.add(new Person("Tom",24,"美国",'M'));
personList.add(new Person("Harley",22,"英国",'F'));
personList.add(new Person("向天笑",20,"中国",'M'));
personList.add(new Person("李康",22,"中国",'M'));
personList.add(new Person("Tom",21,"中国",'F'));
personList.add(new Person("李康",22,"中国",'M'));
//把Person-年龄大于20人--里面名称----新的集合。
List<String> collect = personList.stream().filter(item -> item.getAge() > 20).map(item -> item.getName()).collect(Collectors.toList());
System.out.println(collect);
(5)sorted排序
List<Person> collect1 = personList.stream().sorted((o1, o2) -> o1.getAge() - o2.getAge()).collect(Collectors.toList()); System.out.println(collect1);
(6) reduce规约
归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。

整型集合: -----求和
public class Test4 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> reduce = list.stream().reduce((t1, t2) -> t1 + t2);
System.out.println(reduce.get());
}
}
(7)查询第一个findFirst
Optional<Person> first = personList.stream().filter(t -> t.getAge() >= 18 && t.getAge() <= 20).findFirst();
Person person = first.get();
System.out.println(person);
(8) 去重、合并(distinct、skip、limit)
流也可以进行合并、去重、限制、跳过等操作。
public class Test04 {
public static void main(String[] args) {
String[] arr1 = { "a", "b", "c", "d" };
String[] arr2 = { "d", "e", "f", "g" };
Stream<String> stream1 = Stream.of(arr1);
Stream<String> stream2 = Stream.of(arr2);
// concat:合并两个流 distinct:去重
List<String> collect = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
System.out.println("流合并"+collect);
// limit:限制从流中获得前n个数据
List<String> collect1 = Stream.concat(stream1, stream2).limit(3).collect(Collectors.toList());
System.out.println("limit"+collect1);
// skip:跳过前n个数据 这里的1代表把1代入后边的计算表达式
List<String> collect2 = Stream.concat(stream1, stream2).skip(6).limit(3).collect(Collectors.toList());
System.out.println("skip"+collect);
}
}
(9)
anyMatch:判断的条件里,任意一个元素成功,返回true
allMatch:判断条件里的元素,所有的都是,返回true
noneMatch:与allMatch相反,判断条件里的元素,所有的都不是,返回true
boolean name = personList.stream().anyMatch(t -> t.equals("张无忌"));
System.out.println(name);
(10)接合(joining)
joining可以将stream中的元素用特定的连接符(没有的话,则直接连接)连接成一个字符串。
public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) {
return joining(delimiter, "", "");
}
public class StreamTest {
public static void main(String[] args) {
List<Person> personList = new ArrayList<Person>();
personList.add(new Person("Tom", 8900, 23, "male", "New York"));
personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
String names = personList.stream().map(p -> p.getName()).collect(Collectors.joining(","));
System.out.println("所有员工的姓名:" + names);
List<String> list = Arrays.asList("A", "B", "C");
String string = list.stream().collect(Collectors.joining("-"));
System.out.println("拼接后的字符串:" + string);
}
}
运行结果:

总结:
中间的操作: filter map sorted distinct() skip limit()
终止操作: forEach count() reduce() collect(Collectors.toList()) findFirst match
max min
文章介绍了Java8引入的StreamAPI如何简化集合处理,通过Stream流的思想,实现了对集合的高效过滤、筛选和操作,减少了传统循环遍历的复杂性。StreamAPI的核心包括获取流对象、中间操作和终止操作,提供了filter、map、reduce、collect等多种功能,提高了代码的可读性和性能。

1588

被折叠的 条评论
为什么被折叠?



