首页 > 编程语言 >Java -> Stream入门

Java -> Stream入门

时间:2022-08-26 01:11:21浏览次数:89  
标签:Stream Java 入门 stream List list add new

学习Stream的目的

  • 函数式编程渐渐变成主流,为了看懂同事的代码。

  • 相对于传统的编程方式,代码更为简洁清晰易懂。

  • 使得并发编程变得如此简单。

  • 有效的避免了代码嵌套地狱。(见样例)

    if (条件1) {
        if (条件2) {
            if (条件3) {
                // 再嵌套下去都快见到Diablo了。
            }
        }
    }
    

Stream的特点

  • 不修改数据源:任何对于Stream对象的操作都不会修改数据源的数据。
  • 延迟执行:中间操作只是对于一系列操作细节的定义,而非执行。只有在终端操作被调用的同时执行中间操作。
  • 可消费:任何一个Stream对象执行了终端操作后都将不可再利用。只能操作由数据源生成的新的Stream。

Stream的分类

  • 串行流:单项环境下的Stream,基础。

    List.of().stream();
    
  • 并行流:多线程环境下的Stream,重点难点。本文中未涉及。

    List.of().parallelStream();
    

Stream对象的创建

总共有三种方式:

  • 经由集合对象创建

    List<String> list = new ArrayList<>();
    Stream<String> stream = list.stream();
    
  • 经由数组对象创建(两种)

    String[] strs = new String[10];
    // 将数组所有元素装入stream
    Stream<String> stream1 = Arrays.stream(strs);
    // 将数组指定区间的元素装入stream
    Stream<String> stream2 = Arrays.stream(strs, 1, 7);
    
  • 使用Stream的静态方法创建(三种)

    // 由单个元素创建Stream,元素不允许为null
    Stream<String> stream1 = Stream.of("Test");
    // 由单个元素创建stream,元素允许为null
    Stream<String> stream2 = Stream.ofNullable(null);
    // 由多个元素创建stream,内部其实调用的是Arrays.stream(T[] array)
    Stream<String> stream3 = Stream.of("Test1", "Test2", "Test3");
    

方法的分类

  • 中间操作:根据调用的方法,返回各种各样的stream对象。传入的各种Lambda只是修改了该对象中对应方法的定义,而非执行。
  • 终端操作:执行终端操作的方法,并且其间也执行中间操作对应的方法。

常用方法(入门)

中间操作

distinct

方法签名:Stream<T> distinct()
作用:返回一个去重后的Stream。

List<String> list = List.of("1", "1");
list.stream().distinct()
    .forEach(t -> System.out.println(t)); // 输出:1

filter

方法签名:Stream<T> filter(Predicate<? super T> predicate)
作用:返回一个由满足predicate条件的元素构成的Stream。

List<Integer> list = List.of(1, 3, 5);
list.stream().filter(t -> t >= 3)
    .forEach(t -> System.out.println(t)); // 输出:3, 5

sorted

因为sorted存在两种重载,并且在jdk源码的实现并不相同,所以我们分开讨论。

方法签名:Stream<T> sorted()
作用:通过调用T类型重写Comparable接口的compareTo方法排序,返回排序后的Stream。

// 此处省略了一些java文件定义的结构,请着眼于一下核心代码
// NG例, 不实现Comparable接口
class MyInteger {
    int value;
    MyInteger(int value) {
    	this.value = value;
    }
}
List<MyInteger> list = new ArrayList<>();
list.add(new MyInteger(4));
list.add(new MyInteger(1));
list.add(new MyInteger(3));
list.stream().sorted() // 不报错
    .forEach(t -> System.out.println(t.value)); // ClassCastException:不能被强转成Comparable类型

// OK例, 实现Comparable接口(Integer实现了Comparable接口)
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().sorted()
    .forEach(t -> System.out.println(t)); // 输出:1 3 4

方法签名:Stream<T> sorted(Comparator<? super T> comparator)
作用:通过调用传入的comparator的compare方法排序,返回排序后的Stream。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().sorted((o1, o2) -> o2 - o1) // 传入一个比较器的实现
    .forEach(t -> System.out.println(t.value)); // 输出:4 3 1

skip

方法签名:Stream<T> skip(long n)
作用:返回一个不包含前n项的Stream。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().skip(2) // 跳过前两个元素
    .forEach(t -> System.out.println(t.value)); // 输出:3

limit

方法签名:Stream<T> limit(long n)
作用:返回一个包含前n项的Stream。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().limit(2) // 跳过前两个元素
    .forEach(t -> System.out.println(t.value)); // 输出:4 1

peek

方法签名:Stream<T> peek(Consumer<? super T> action)
作用:执行消费操作,返回原Stream。虽然有消费操作,但是Stream的状态并不会改变。并不会真正消费Stream这一特点是的peek方法常用于调试。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Stream<Integer> stream = list.stream();
stream.peek(t -> System.out.println(t)); // 输出:4 1 3, 并且不消费stream
stream.forEach(t -> System.out.println(t)); // 输出:4 1 3, 并且消费stream(消费后stream不可再次使用)
stream.forEach(t -> System.out.println(t)); // IllegalStateException:stream已经被操作或关闭

map

方法签名:Stream<T> map(Function<? super T, ? extends R> mapper)
作用:将原Stream中的所有元素类型从T转化为R(不是强转,是通过一些操作得到R类型),返回封装R类型元素的Stream。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().map(t -> String.valueOf(t)) // 将元素都转换成String
    .forEach(t -> System.out.println(t)); // 输出:4 1 3

flatMap

方法签名:Stream<T> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
作用:将原Stream中的所有元素类型从T转化为R,返回Stream<R>。与map的主要区别在于,适配一对多的数据类型。比如,类型T中存在一个List<String>,使用map返回一个Stream<List<String>>,而是用flatMap则返回一个Stream<String>,实现一对多的映射。

List<Integer[]> list = new ArrayList<>();
list.add(new Integer[] {1, 2, 3});
list.add(new Integer[] {4, 5, 3});
list.stream().flatMap(t -> Stream.of(t)) // 将各个数组中的元素都放入stream, 实现 1 → n 的转换
    .forEach(t -> System.out.println(t)); // 输出:1 2 3 4 5 3

终端操作

forEach

方法签名:void forEach(Consumer<? super T> action)
作用:迭代消费Stream里的所有元素,比如打印,写入文件,写入DB等。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().forEach(t -> System.out.println(t)); // 输出:4 1 3

toArray

方法签名:Object[] toArray()
作用:将Stream中的所有元素封装成Object[]返回。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Object[] objects = list.stream().toArray(); // 与元素类型无关, 固定返回Object[]
Integer[] ints = (Integer[])objects; // 使用时你可能需要类型强转

count

方法签名:long count()
作用:返回Stream中的元素个数。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
long count = list.stream().count(); // 返回stream中的元素个数, 当前为3

findFirst

方法签名:Optional<T> findFirst()
作用:Stream的第一个元素封装在Optional中返回。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Optional<Integer> first = list.stream().findFirst(); // 返回stream中的第一个元素, 当前为4
/* 
	Optional类内容比较多所以现在不做赘述, 大家姑且就认为是个只能存放一个元素的容器就好,以后会开一个新的博文详细为	大家讲解用法
 */

anyMatch

方法签名:boolean anyMatch(Predicate<? super T> predicate)
作用:当存在符合predicate条件的元素时返回true,否则返回false。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
boolean bool = list.stream().anyMatch(t -> t <= 1); // 当一个元素小于等于1时就返回true, 当前true

allMatch

方法签名:boolean allMatch(Predicate<? super T> predicate)
作用:当所有元素都符合predicate条件时返回true,否则返回false。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
boolean bool = list.stream().allMatch(t -> t <= 1); // 当所有元素小于等于1时才返回true, 当前false

noneMatch

方法签名:boolean noneMatch(Predicate<? super T> predicate)
作用:当所有元素都不符合predicate条件时返回true,否则返回false。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
boolean bool = list.stream().noneMatch(t -> t <= 1); // 当所有元素都不小于等于1时才返回true, 当前false

min

方法签名:Optional<T> min(Comparator<? super T> comparator)
作用:按照传入的比较器将最小的元素封装在Optional中返回。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Optional<Integer> min = list.stream().min((o1, o2) -> o2 - o1); // 根据传入的比较器实现返回最小值, 当前4
/*
	这个方法可以认为stream按照传入的比较器排序, 返回排序后的第一个元素
 */

max

方法签名:Optional<T> max(Comparator<? super T> comparator)
作用:按照传入的比较器将最大的元素封装在Optional中返回。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Optional<Integer> max = list.stream().max((o1, o2) -> o2 - o1); // 根据传入的比较器实现返回最大值
/*
	这个方法可以认为stream按照传入的比较器排序, 返回排序后的最后一个元素
 */

本文只讨论了串行流的使用方法,对于并行流等进阶的使用方法请参考 Java -> Stream进阶(尚未更新)

标签:Stream,Java,入门,stream,List,list,add,new
From: https://www.cnblogs.com/buzuweiqi/p/16616100.html

相关文章

  • 05.爬虫入门笔记1
    入门爬虫笔记011.request库的使用使用request库的get方法importrequestr=request.get('www.baidu.com')这会得到一个Response对象,将其存入变量r。显示得到的......
  • RabbitMQ 入门系列:5、基础编码:交换机的进阶介绍及编码方式。
    系列目录RabbitMQ入门系列:1、MQ的应用场景的选择与RabbitMQ安装。RabbitMQ入门系列:2、基础含义:链接、通道、队列、交换机。RabbitMQ入门系列:3、基础含义:持久化......
  • java中的字符流知识点总结
    java中字符流字符流:对文本的读取,速度比字节流快常见的字符流:Reader和WriterReader是InputStreamReader的父类,InputStreamReader是FileReader的父类FileReader的相......
  • windows下的Sonarqube+Sonar-Scanner简单入门配置
    参考:https://blog.csdn.net/weixin_40496191/article/details/120250953https://www.cnblogs.com/longpizi/p/12376500.htmlsonar文档:https://docs.sonarqube.org/lates......
  • idea新建Java项目
    一、方法一1、打开idea选择NewProject新建项目2、选择Java项目,并指定jdk版本点击Next3、再次点击Next4、指定项目名称,及项目位置指定项目名称,及项目位置后,点......
  • JAVA BigDecimal
    加减乘除BigDecimalqtySettleTotal=qtySettleTotal.setScale(2,BigDecimal.ROUND_HALF_UP);BigDecimalqtyYF=this.txtqtyYF.getBigDecimalValue().setScale(2,B......
  • JavaScript快速入门-06-函数
    6函数6.1函数定义  函数可以封装语句,然后在任何地方、任何时间执行。JavaScript中的函数使用function关键字声明,主要由函数名、函数参数和函数体组成。其基本语法......
  • C++入门第一课 函数声明与定义
    函数的声明:如:voidLog(constchar*message);1,在C++中,函数原型就是函数的声明。函数声明就是给函数取名并指定函数的参数类型,返回值类型。告诉编译器有这么一个可使用的......
  • Mysql入门练习题
    1、在students表中,查询年龄大于25岁,且为男性的同学的名字和年龄mysql>selectname,agefromstudentswhereage>25andgender='M';+---------------+-----+|name......
  • 10.Java中Map的entrySet() 详解以及用法
    一、Map.entry是什么?Map是java中的接口,Map.Entry是Map的一个内部接口。此接口为泛型,定义为Entry<K,V>。它表示Map中的一个实体(一个key-value对)接口中有get......