Stream常用方法
 Stream流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:
 终结方法:返回值类型不再是 Stream 类型的方法,不再支持链式调用。本小节中,终结方法包括 count 和 forEach 方法。
非终结方法:返回值类型仍然是 Stream 类型的方法,支持链式调用。(除了终结方法外,其余方法均为非终结 方法。)
Stream注意事项(重要)
 我们学习了Stream的常用方法,我们知道Stream这些常用方法可以分成两类,终结方法,函数拼接方法
Stream的3个注意事项:
Stream只能操作一次
Stream方法返回的是新的流
Stream不调用终结方法,中间的操作不会执行
集合处理数据的弊端
 当我们需要对集合中的元素进行操作的时候,除了必需的添加、删除、获取外,最典型的就是集合遍历。我们来体验 集合操作数据的弊端,需求如下:
一个ArrayList集合中存储有以下数据:
张无忌,周芷若,赵敏,张强,张三丰
需求:
1.拿到所有姓张的
2.拿到名字长度为3个字的
3.打印这些数据
代码如下:
public static void main(String[] args) {
    // 一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,张强,张三丰
    // 需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据
    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰");
    // 1.拿到所有姓张的
    ArrayList<String> zhangList = new ArrayList<>(); // {"张无忌", "张强", "张三丰"}
    for (String name : list) {
     if (name.startsWith("张")) {
       zhangList.add(name);
     }
 }
    // 2.拿到名字长度为3个字的
    ArrayList<String> threeList = new ArrayList<>(); // {"张无忌", "张三丰"}
    for (String name : zhangList) {
      if (name.length() == 3) {
       threeList.add(name);
     }
    }
    // 3.打印这些数据
    for (String name : threeList) {
      System.out.println(name);
    }
 }
 循环遍历的弊端
这段代码中含有三个循环,每一个作用不同:
首先筛选所有姓张的人;
然后筛选名字有三个字的人;
最后进行对结果进行打印输出。
每当我们需要对集合中的元素进行操作的时候,总是需要进行循环、循环、再循环。这是理所当然的么?不是。循环 是做事情的方式,而不是目的。每个需求都要循环一次,还要搞一个新集合来装数据,如果希望再次遍历,只能再使 用另一个循环从头开始。
那Stream能给我们带来怎样更加优雅的写法呢?
Stream的更优写法
下面来看一下借助Java 8的Stream API,修改后的代码:
public class Demo03StreamFilter {
 public static void main(String[] args) {
    List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
        list.stream()
                    .filter(s -> s.startsWith("张"))
                    .filter(s -> s.length() == 3)
                    .forEach(System.out::println);
    }
 }
 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印。我们真 正要做的事情内容被更好地体现在代码中。
Stream流式思想概述
 注意:Stream和IO流(InputStream/OutputStream)没有任何关系,请暂时忘记对传统IO流的固有印象!
Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工 处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。
Stream API能让我们快速完成许多复杂的操作,如筛选、切片、映射、查找、去除重复,统计,匹配和归约。
小结
首先我们了解了集合操作数据的弊端,每次都需要循环遍历,还要创建新集合,很麻烦 Stream是流式思想,相当于工厂的流水线,对集合中的数据进行加工处理
Stream流的forEach方法
 forEach 用来遍历流中的数据
void forEach(Consumer<? super T> action);
该方法接收一个 Consumer 接口函数,会将每一个流元素交给该函数进行处理。例如:
@Test
 public void testForEach() {
   List<String> one = new ArrayList<>();
    Collections.addAll(one, "迪丽热巴", "宋远桥", "苏星河", "老子", "庄子", "孙子");
   /*one.stream().forEach((String s) -> {
    System.out.println(s);
    });*/
   // 简写
    // one.stream().forEach(s -> System.out.println(s));
    one.stream().forEach(System.out::println);
 }
 Stream流的count方法
Stream流提供 count 方法来统计其中的元素个数:
long count();
该方法返回一个long值代表元素个数。基本使用:
@Test
 public void testCount() {
    List<String> one = new ArrayList<>();
    Collections.addAll(one, "迪丽热巴", "宋远桥", "苏星河", "老子", "庄子", "孙子");
    System.out.println(one.stream().count());
 }
 Stream流的filter方法
filter用于过滤数据,返回符合过滤条件的数据
可以通过 filter 方法将一个流转换成另一个子集流。方法声明:
Stream<T> filter(Predicate<? super T> predicate);
该接口接收一个 Predicate 函数式接口参数(可以是一个Lambda或方法引用)作为筛选条件。
Stream流中的 filter 方法基本使用的代码如:
@Test
 public void testFilter() {
   List<String> one = new ArrayList<>();
    Collections.addAll(one, "迪丽热巴", "宋远桥", "苏星河", "老子", "庄子", "孙子");
   one.stream().filter(s -> s.length() == 2).forEach(System.out::println);
 }
 在这里通过Lambda表达式来指定了筛选的条件:姓名长度为2个字。
Stream流的limit方法
 limit 方法可以对流进行截取,只取用前n个。方法签名:
Stream<T> limit(long maxSize);
参数是一个long型,如果集合当前长度大于参数则进行截取。否则不进行操作。基本使用:
@Test
 public void testLimit() {
 List<String> one = new ArrayList<>();
    Collections.addAll(one, "迪丽热巴", "宋远桥", "苏星河", "老子", "庄子", "孙子");
    one.stream().limit(3).forEach(System.out::println);
 }
 Stream流的skip方法
 如果希望跳过前几个元素,可以使用 skip 方法获取一个截取之后的新流:
Stream<T> skip(long n);
如果流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0的空流。基本使用:
@Test
 public void testSkip() {
    List<String> one = new ArrayList<>();
    Collections.addAll(one, "迪丽热巴", "宋远桥", "苏星河", "老子", "庄子", "孙子");
    one.stream().skip(2).forEach(System.out::println);
 }
 Stream流的map方法
如果需要将流中的元素映射到另一个流中,可以使用 map 方法。方法签名:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
该接口需要一个 Function 函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的流。
Stream流中的 map 方法基本使用的代码如:
@Test
 public void testMap() {
    Stream<String> original = Stream.of("11", "22", "33");
    Stream<Integer> result = original.map(Integer::parseInt);
    result.forEach(s -> System.out.println(s + 10));
 }
 这段代码中, map 方法的参数通过方法引用,将字符串类型转换成为了int类型(并自动装箱为 Integer 类对象)。 作者:木子教程 https://www.bilibili.com/read/cv14222552 出处:bilibili










