Stream流学习笔记

本文详细介绍了JavaStreamAPI中的各种操作,包括创建流的方式、中间操作如filter、map、distinct、sorted、limit、skip和flatMap,以及终结操作如forEach、count、max/min、collect等,并展示了如何使用这些操作进行数据处理和查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

创建流

单例集合:集合对象.stream()

List<Integer> list = new ArrayList<>();
Stream<Integer> stream = list.stream();

数组:Arrays.stream(数组) 或 Stream.of(数组) 来创建

Integer[] arr = {1,2,3,4};
Stream<Integer> stream1 = Arrays.stream(arr);
Stream<Integer> stream2 = Stream.of(arr);

双例集合:转换成单例集合后再创建

Map<String, String> map = new HashMap<>();
Stream<Map.Entry<String, String>> stream3 = map.entrySet().stream();

中间操作

1、filter

对流中的元素进行条件过滤,符合过滤条件的才能继续留在流中。

public static void test() {
    List<Author> authors = getAuthors();
    authors.stream()
            .filter(author -> author.getAge() > 18) //中间操作
            .forEach(author -> System.out.println(author)); //终结操作
}

2、map

可以把流中的元素进行计算或转换。

转换:

public static void test() {
    List<Author> authors = getAuthors();
    //泛型中,第一个参数为方法的参数类型,第二个参数为方法的返回值类型
    authors.stream()
            .map(author -> author.getName())
            .forEach(name -> System.out.println(name));
}

3、distinct

去除流中的重复元素。

注意:distinct方法是依赖Object的equals方法来判断是否是相同对象,所以需要重写equals方法。

4、sorted

对流中的元素进行排序。

方式一:调用sorted()空参方法
在比较的实体类上要实现Comparable接口,不然会报类型不匹配的异常。

image-20240212122159278

public static void test2() {
    List<Author> authors = getAuthors();
    authors.stream()
            .distinct()
            .sorted()
            .forEach(author -> System.out.println(author.getAge()));
}

方式二:在sorted方法中实现Comparator接口

public static void test2() {
    List<Author> authors = getAuthors();
    authors.stream()
            .distinct()
            .sorted(new Comparator<Author>() {
                @Override
                public int compare(Author o1, Author o2) {
                    return o1.getAge()-o2.getAge();
                }
            })
            .forEach(author -> System.out.println(author.getAge()));
}

优化

public static void test2() {
    List<Author> authors = getAuthors();
    authors.stream()
            .distinct()
            .sorted((o1, o2) -> o1.getAge()-o2.getAge())
            .forEach(author -> System.out.println(author.getAge()));
}

5、limit

可以设置流的最大长度,超出的部分将被抛弃。

//对流中的元素按照年龄进行降序排序,并且要求不能有重复元素,打印其中年龄最大的两个作家。
public static void test2() {
    List<Author> authors = getAuthors();
    authors.stream()
            .distinct()
            .sorted((o1, o2) -> o2.getAge()-o1.getAge())
            .limit(2)
            .forEach(author -> System.out.println(author.getName()));
}

6、skip

跳过流中的前n个元素,返回剩下的元素。

7、flatMap

map只能把一个对象转换成另一个对象来作为流中的元素。而flatMap可以把一个对象转换成多个对象作为流中的元素。

案例1:打印所有书籍的名字,要求对重复的元素进行去重。
map方式:Author对象的books属性是集合类型,使用原来map转换对象,要使用嵌套循环进行打印。

public static void test2() {
    List<Author> authors = getAuthors();
    authors.stream()
            .map(author -> author.getBooks())
            .forEach(books -> {
                for (Book book : books) {
                    System.out.println(book.getName());
                }
            });
}

flatMap方式:

public static void test2() {
    List<Author> authors = getAuthors();
    authors.stream()
            .flatMap(author -> author.getBooks().stream())
            .forEach(book -> System.out.println(book.getName()));
}

案例二:打印现有数据的所有分类,要求对分类进行去重。不能出现这种格式:哲学,爱情,要将它们拆开输出。

public static void test3() {
    List<Author> authors = getAuthors();
    authors.stream()
            .flatMap(author -> author.getBooks().stream())
            .distinct()
            .flatMap(book -> Arrays.stream(book.getCategory().split(",")))
            .distinct()
            .forEach(category -> System.out.println(category));
}

终结操作

1、forEach

对流中的元素进行遍历操作,我们通过传入的参数去指定对遍历到的元素进行什么具体操作。

2、count

获取当前流中元素的个数。

//打印这些作家的所出书籍的数量
public static void test4() {
    List<Author> authors = getAuthors();
    long count = authors.stream()
            .flatMap(author -> author.getBooks().stream())
            .distinct()
            .count();
    System.out.println(count);
}

3、max&min

获取流中的最值

//分别获取这些作家所出书籍的最高分和最低分
public static void test4() {
    List<Author> authors = getAuthors();
    Optional<Integer> max = authors.stream()
            .flatMap(author -> author.getBooks().stream())
            .map(book -> book.getScore())
            .max((o1, o2) -> o1 - o2);
    Optional<Integer> min = authors.stream()
            .flatMap(author -> author.getBooks().stream())
            .map(book -> book.getScore())
            .min(((o1, o2) -> o1 - o2));
    System.out.println(max.get());
    System.out.println(min.get());
}

4、collect

把当前流转换成一个集合。

list集合

//获取一个存放所有作者名字的list集合
public static void test5() {
    List<Author> authors = getAuthors();
    List<String> nameList = authors.stream()
            .map(author -> author.getName())
            .collect(Collectors.toList());
    System.out.println(nameList);
}

set集合

//获取一个存放所有作者名字的set集合
public static void test5() {
    List<Author> authors = getAuthors();
    Set<String> nameList = authors.stream()
            .map(author -> author.getName())
            .collect(Collectors.toSet());
    System.out.println(nameList);
}

map集合

//获取一个Map集合,map的key为作者名,value为List<Book>
public static void test5() {
    List<Author> authors = getAuthors();
    Map<String, List<Book>> map = authors.stream()
            .distinct()
            .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
    System.out.println(map);
}

5、查找与匹配

(1)anyMatch:判断是否有任意符合匹配条件的元素,结果为boolean类型。

//判断是否有作家年龄在18以上
public static void test6() {
    List<Author> authors = getAuthors();
    boolean flag = authors.stream()
            .anyMatch(author -> author.getAge() > 18);
    System.out.println(flag);
}

(2)allMatch:判断是否都符合条件,如果都符合返回true,否则返回false

//判断是否所有作家年龄在18以上
public static void test6() {
    List<Author> authors = getAuthors();
    boolean flag = authors.stream()
            .allMatch(author -> author.getAge() > 18);
    System.out.println(flag);
}

(3)noneMatch:判断流中的元素是否都不符合匹配条件,如果都不符合结果为true,否则结果为false。

(4)findAny:获取流中的任意一个元素。该方法没有办法保证获取到的一定是流中的第一个元素。

//获取任意一个年龄大于18的作家,如果存在就输出他的名字
public static void test7() {
    List<Author> authors = getAuthors();
    Optional<Author> any = authors.stream()
            .filter(author -> author.getAge() > 18)
            .findAny();
    //如果这个Optional中有元素,则执行方法,没有就不执行
    any.ifPresent(author -> System.out.println(author.getName()));
}

(5)findFirst:获取流中的第一个元素。

//获取一个年龄最小的作家,并输出他的姓名
public static void test7() {
    List<Author> authors = getAuthors();
    Optional<Author> any = authors.stream()
            .sorted((o1, o2) -> o1.getAge()-o2.getAge())
            .findFirst();
    any.ifPresent(author -> System.out.println(author.getName()));
}

(6)reduce归并
对流中的数据按照你指定的计算方式计算出一个结果。(缩减操作)

reduce的作用是把stream中的元素给组合起来。我们可以传入一个初始值,它会按照我们的计算方式依次拿流中的元素和初始化值进行计算,计算结果再和后面的元素计算。

它内部的计算方式如下:

T result = identity;
for (T element : this stream)
	result = accumulator.apply(result, element)
return result;

其中identity就是我们可以通过方法参数传入的初始值,accumulator的apply具体进行什么计算也是我们通过方法参数来确定的。

案例1:使用reduce求所有作者年龄的和

public static void test8() {
    List<Author> authors = getAuthors();
    Integer sum = authors.stream()
            .distinct()
            .map(author -> author.getAge())
            //初始值为0,后面 result+=element,最后 return result
            .reduce(0, (result, element) -> result + element);
    System.out.println(sum);
}

案例2:使用reduce求所有作者中年龄的最大值

public static void test8() {
    List<Author> authors = getAuthors();
    Integer max = authors.stream()
            .map(author -> author.getAge())
            .reduce(Integer.MIN_VALUE, (result, element) -> result > element ? result : element);
    System.out.println(max);
}

reduce有个重载形式,内部代码如下:

boolean foundAny = false;
T result = null;
for (T element : this stream) {
	if(!foundAny) {
		foundAny = true;
		result = element;
	} else {
		result = accumulator.apply(result, element);
	}
}
return foundAny ? Optional.of(result) : Optional.empty();

利用这个重载形式,求作者年龄的最大值,不用传递初始值了。

public static void test8() {
    List<Author> authors = getAuthors();
    Optional<Integer> max = authors.stream()
            .map(author -> author.getAge())
            .reduce((result, element) -> result > element ? result : element);
    System.out.println(max.get());
}

注意事项
惰性求值:如果没有终结操作,中间操作是不会得到执行的。

流是一次性的:一旦一个流对象经过一个终结操作后,这个流就不能再被使用了,只能重新创建流对象再使用。

不会影响原数据:我们在流中可以对数据做很多处理,但正常情况下是不会影响原来集合中的元素的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gunalaer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值