Skip to content

day13【lambda 和 Stream】

今日内容介绍

java
Lambda表达式
函数式接口
Stream流
java
能够理解函数式编程相对于面向对象的优点
能够掌握Lambda表达式的标准格式
能够掌握Lambda表达式的省略格式与规则
能够使用Consumer<T>函数式接口
能够使用Predicate<T>函数式接口
能够理解流与集合相比的优点

第一章 Lambda 表达式

java
在数学中,函数指的是有输入量、有输出量的一套计算方案。也就是"拿什么东西做什么事情"--功能
相对于面向对象思想,先有对象,再调功能。"必须有对象才能做事情",而函数式的思想---强调做什么,不强调怎么做。

1.1 函数式编程思想和 Lambda 表达式体验

java
package com.itheima.lambda;

public interface Swimming {

    void swim();
}

package com.itheima.lambda;

public class LambdaDemo1 {


    public static void main(String[] args) {


        //怎么调用goSwimming方法 ?
//        goSwimming();//需要什么类型传什么类型对象 --现在的思想
       //如果这个类型 是接口类型 Swimming  只能采用子类对象
        // 1:去外面创建一个实现类 实现该接口 ----重写 swim方法
        //2:在当前采用匿名内部类方式 实现该接口  ---重写swim方法
        Swimming swimming = new Swimming() {
            @Override
            public void swim() {
                System.out.println("铁汁,咱们游泳吧");
            }
        };

        //可以调用方法
        goSwimming(swimming);

    }


    public static void goSwimming(Swimming swimming) {

         swimming.swim();
    }
}

lambda
package com.itheima.lambda;

public class LambdaDemo2 {


    public static void main(String[] args) {


        goSwimming(()->{ System.out.println("铁汁,咱们游泳吧");});

    }


    public static void goSwimming(Swimming swimming) {

         swimming.swim();
    }
}

1.2 Lambda 表达式的标准格式

java
Lambda表达式 省去了面向对象的条条框框
     ()->{}
 格式有三部分组成
   () 一些参数   方法参数列表一样  拿什么东西
   -> 一个箭头   做--
   {} 一段代码   什么事
 标准格式
 (参数列表)->{代码体(方法体)}
在这里方法的名字不重要,方法 拿什么干什么事最重要。

格式要求:

java
小括号内的语法 与之前方法参数列表一致。无参数是空,有参数之间用,隔开。
->都是英文符号,代表动作  "干"
大括号与之前方法体一致。

Lambda 适合 什么情况呢

适合使用在 方法的参数需要的 一个接口 并且该接口只有一个抽象方法,这种情况,lambda 可以理解为代替了该方法。(重写方法)

1.3 Lambda 表达式 (省略的方法)无参无返回值

java
package com.itheima.lambda2;

public class LambdaDemo01 {

    public static void main(String[] args) {
        //Runnable接口 创建线程对象并启动
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("执行线程任务");
            }
        };

        new Thread(runnable).start();

        /*
          我们上面的调用方式  是面向对象思想
              怎么做
                 需要一个类型 那么就得构建出来对象  --使用匿名内部类方式
                 还得重写run方法

              让谁做
                 Thread构造中传递了 runnable对象,启动线程之后 由 runnable对象调用 run方法

             本质 就是 执行    System.out.println("执行线程任务"); 这段代码
         */
        /*
          函数式编程思想
             拿什么东西干什么事 !

         */
  new Thread(()-> System.out.println("淦就完了")).start();
          //当你的参数是接口的时候 并且接口里面只有一个功能  因为多了不能进行可推导可省略了
    }
}

1.3 Lambda 表达式 (省略的方法)有参数有返回值

java
package com.itheima.lambda2;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class LambdaDemo02 {
    public static void main(String[] args) {
        ArrayList<Person> list = new ArrayList<>();
        list.add(new Person("张三",14));
        list.add(new Person("李四",17));
        list.add(new Person("王五",16));
        list.add(new Person("赵六",18));

        System.out.println(list);
        //能不能完成 按照年龄进行 从小打大的顺序 对集合进行排序
        // 要求  你使用之前方式做
                             //格式重要吗 不重要 格式出来的目的 做事  拿参数o1 o2 做事
        Collections.sort(list, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                // 按照 person对象的age属性 完成升序
                // 升序 前-后
                return o1.getAge()-o2.getAge();
            }
        });

    }
}

改进

java
 // 面向对象思想没错  我们依旧可以采用
        // lambda表达式思想  拿什么东西 干 什么事
        //  我们参数必须是接口,并且接口有且只有一个抽象方法。 lambda是就是来替代抽象方法的实现的
        // 让方法的实现变得更加的直接
//        Collections.sort(list,(Person o1,Person o2)->{
//                                  return o1.getAge()-o2.getAge();
//                               });
//
        //省略模式的
        Collections.sort(list,(o1, o2)->o1.getAge()-o2.getAge());

        System.out.println("排好顺序的:"+list);

1.4 Lambda 表达式的省略格式

既然是 可推到可省略的思想体现,哪能不能再来简单点呢?

可省略的语法

java
1:小括号里面的参数类型可以省略。
2:如果小括号里面有且只有一个参数,小括号都可以省略。
3:如果大括号里面有且只有一条语句,无论是否有返回值,都可以省略大括号。
              注意 如果带参数的使用了这个语法 return也得省略。分号也得省。
java
省略后 线程的代码
  new Thread(()->System.out.println("我是新的线程:"+Thread.currentThread().getName())).start();
省略后 排序的代码
 Collections.sort(list,(o1, o2)->  o1.getAge()-o2.getAge());

更加的理解了 可推到可省略思想 以及 函数式编程思想 重点在 在做什么 而不是怎么做。

1.5 Lambda 表达式的前提

java
Lambda表达式比起之前代码看起来会更简洁。虽然操作很方便,但是是有使用前提的。
使用的前提是:
1:使用Lambda表达式的地方 必须有接口,而且该接口有且只有一个抽象方法。比如用的Runnable接口,Callable接口, Comparator接口 ,都是有且只有一个抽象方法。
2: 使用Lambda表达式一般用在方法的参数上,也就是说参数上必须是一个有且只有一个抽象方法的接口,我们才可以使用lambda表达式去省略。
 我们JDK8把这种有且只有一个抽象方法的接口,称为函数式接口!!
  可以自己定义 也可以使用JDK提供的。

注解 @FunctionalInterface //注解 是用来判断是不是函数式接口的。

1641956682173

1641956697819

1.6 自定义函数式接口

java
package com.itheima.lambda3;

public interface MyFunctionInterface {
    //有且只有一个抽象方法
    void makeMoney();
}

怎么用

java
package com.itheima.lambda3;

public class Demo {

    public static void main(String[] args) {

        money(new MyFunctionInterface() {
            @Override
            public void makeMoney() {
                System.out.println("自己花美元,去美国花!");
            }
        });

        money(()-> System.out.println("自己造日元,在日本花"));
    }

    public static void money(MyFunctionInterface myFunctionInterface) {
           myFunctionInterface.makeMoney();
    }
}

第二章 函数式接口

Lambda 其实就是简化函数式接口的使用。

从应用的层面来说:java 中 lambda 是简化了匿名内部类格式,但是两者的原理是不一样的。

1628564834291

**函数式接口:**有且只有一个抽象方法的接口。

格式:

java
public interface 接口名 {
    //有且只有一个抽象方法
}

这样的接口我们可以自己定义,也可以使用官方提供的一些,除了我们之前知道的 Runnabale Callable Comparator 这些以外,还有一些常见的函数式接口(JDK8 才出现的)。

@FunctionalInterface  注解可以标明,该接口是一个函数式接口。

常用的函数式接口

2.1 Supplier(生产)接口的 get 方法

java
java.util.function.Supplier<T>接口,它意味着"供给",
对应的Lambda表达式需要对外提供一个符合泛型类型的对象数据。

接口中有泛型,泛型指的是,你这个接口中的方法 生产 什么类型对象!
说白了 这个接口主要 用于产生对应类型的数据。

所以它的方法叫get
     T get() 方法里面 你要去实现  数据的产生过程,然后返回一个对象。
     get方法 定义了 生产。至于生产什么 由方法体完成!!
java
package com.itheima.lambda4;

import java.util.function.Supplier;

public class SupplierDemo {
    /*
    JDK8 提供了一个 "供给" 生产型接口 Supplier
      里面只有一个抽象方法  T get()  只出不进

      因为是函数式接口 所以我们只需要在使用 该接口的地方  使用lambda表达式完成

      函数式接口 出现在方法
     */
    public static void main(String[] args) {

        //按照以前思路 是不是要 接口实现类 或者匿名内部类对象  重写get方法 返回一个最大值。

        int a = 10;
        int b = 20;

        // lambda 思想 直接干事
        printMax(()->{return a>b?a:b;});

        String s = "aBssaB";

        String ss = getString(()->{return s.toUpperCase();});

        System.out.println(ss);
    }
    /*
        传递 一个 生产型接口
            根据生产型接口 返回一个最大值
            输出打印最大值
     */
    public static void printMax(Supplier<Integer> supplier){
        Integer max = supplier.get();//这里的功能 求出最大值的功能  由调用者实现
        System.out.println(max);
    }


    /*
        我们可以把一个字符串数据 转换成一个 全部大写的 字符串
     */
    public static String getString(Supplier<String> supplier){
        return  supplier.get();
    }
}

2.2 Supplier 接口的 get 方法练习求数组最大值

java
package com.itheima.lambda4;

import java.util.function.Supplier;

/*
 Supplier  是一个生产接口
   泛型  指的就是 生产什么样的类型数据

   里面 功能叫
    T get() 这定义了生产方法
      至于生产什么 自己定义。

      怎么定义 在调用 该接口作为参数的方法的时候 用lambda表达式完成生产!
 */
public class SupplierDemo {

    public static void main(String[] args) {
       int[] arr = {2,3,3,3,22,12};

        //调用printMax()  能够得到 数组的最大值
    }

    public static void printMax(Supplier<Integer> supplier){
        Integer max = supplier.get();
        System.out.println(max);
    }






}

2.3 Consumer 接口的 accept 方法

java
java.util.function.Consumer<T>接口则正好相反,它不是生产一个数据,而是消费一个数据其数据类型由泛型参数决定。
    T 需要消费的 数据的类型,调用该对象的属性 方法就可以理解为消费。玩对象的内容。

   void accept(T t) 接受 接收 方法  你给我啥类型对象,我都行,我能消费!
java
package com.itheima.lambda4;

import java.util.function.Consumer;

public class ConsumerDemo {
    /*
    Consumer  消费型接口
        里面的功能  有参数无返回值
                void accept(T t)
     */
    public static void main(String[] args) {
          String s = "给你一张卡,随便消费,余额是1000000000000";

          xiaofei(s,(String s1)->{
              System.out.println(s1.substring(11));
          });
    }

    public static void xiaofei(String s, Consumer<String> consumer){

        consumer.accept(s);//我们消费一个 字符串  怎么消费你定义
    }
}

1641958845824

本质的参数传递

1641958859281

2.4 Function 接口的 apply 方法

java
Function转换型接口  既有输入又有输出。

Fuction<T,R>

  T  输入类型

  R  输入类型

把输入类型转换成输出类型。

Fuction<String,Integer>

把String转换成Integer

方法

​      R apply(T t)
java
package com.itheima.lambda4;

import java.util.function.Function;

public class FunctionDemo {
    /**
     * Function转换型接口  既有输入又有输出。
     *
     * Fuction<T,R>
     *
     *   T  输入类型
     *
     *   R  输入类型
     *
     * 把输入类型转换成输出类型。
     *
     * Fuction<String,Integer>
     *
     * 把String转换成Integer
     *
     * 方法
     *
     * ​      R apply(T t)
     */

    public static void main(String[] args) {
        String s = "12345";

//        Integer result = change(s, (String str) -> {
//            return Integer.parseInt(str);
//        });

        Integer result = change(s, str ->Integer.parseInt(str));

        System.out.println(result);
    }

    /**
     * 功能 是可以把 字符串转换成Integer数据类型
     *   至于是怎么完成转换的 由lambda去实现
     */
    public static Integer change(String input, Function<String,Integer> function){

        return function.apply(input);
    }
}

2.5 Predicate 的 test 方法

java
判断接口 Predicate
有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果,这时可以使用java.util.function.Predicate<T>接口。
  boolean test(T t)
    泛型 T 代表我们要进行判断的主题,至于怎么判断lambda
java
package com.itheima.lambda4;

import java.util.function.Predicate;

public class PredicateDemo {
    /**
     * 判断接口 Predicate
     * 有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果,这时可以使用java.util.function.Predicate<T>接口。
     *   boolean test(T t)
     *     泛型 T 代表我们要进行判断的主题,至于怎么判断lambda
     */
    public static void main(String[] args) {
       String longStr = "我是如来佛祖玉皇大帝指定取西经特派使者花果山水帘洞美猴王齐天大圣孙悟空";

       // 你想写啥规则 就往 lambda写
       boolean flag = panduan(longStr,(str)->{return str.length()>=16;});

        System.out.println("字符串长吗?"+flag);

        boolean flag2 = panduan(longStr,str->str.contains("弼马温"));

        System.out.println("这个字符串包含 弼马温 吗?"+flag2);
     }
    /**
     * 实现一个功能表示判断
     *   这里没有实现判断什么  接口只定义功能 具体怎么实现  lambda实现
     */
    public static boolean panduan(String str , Predicate<String> predicate){

        return predicate.test(str);
    }
}

第三章 Stream 流

流简单理解就是流水线作业,它只做数据的处理,不做数据的保留。

如果想用流,先要将数据放入流中,数据在流中进行流水线作业,产出最终的数据,需要被收集到指定容器中。

容器可以是集合也可以是数组。

3.1 Stream 流的体验

java
/*
    需求:从List集合中按照以下条件筛选出符合条件的数据
        1. 首先筛选所有姓张的人;
        2. 然后筛选名字有三个字的人;
        3. 最后进行对结果进行打印输出。
    通过传统的操作集合的方式
 */
package com.itheima.stream;

import java.util.ArrayList;
import java.util.List;

public class Demo {
    /**
     *     需求:从List集合中按照以下条件筛选出符合条件的数据
     *         1. 首先筛选所有姓张的人;
     *         2. 然后筛选名字有三个字的人;
     *         3. 最后进行对结果进行打印输出。
     *     通过传统的操作集合的方式

     */
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");
        // 首先筛选所有姓张的人;
        List<String> zhangList = new ArrayList<>();
        //遍历筛选
        for (String name : list) {
            if(name.startsWith("张")){
                zhangList.add(name);
            }
        }

        // 筛选名字有三个字的人
        List<String> threeList = new ArrayList<>();
        for (String s : zhangList) {
            if(s.length()==3){
                threeList.add(s);
            }
        }
        //最后进行对结果进行打印输出。
        for (String s : threeList) {
            System.out.println(s);
        }

    }
}
java
package com.itheima.stream;

import java.util.ArrayList;
import java.util.List;

public class StreamDemo02 {
    public static void main(String[] args) {
       /*
         List集合
            对集合进行筛选过滤
              1:首先筛选出 所有姓 张的人
              2: 继续筛选 名字有三个字的人
              3: 最后对结果进行输出打印
        */
       List<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张三丰");
        list.add("小昭");
        list.add("张三");
        //就是让我们的集合中的元素接下来进行流水线作业
          list.stream().filter(name->name.startsWith("张")).filter(s->s.length()==3).forEach(name->System.out.println(name));
    }
}

3.2 流式思想的介绍

1628579016245

3.3 获取 Stream 流的方式

1628579165848

java
package com.itheima.stream;

import java.util.*;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class ToStream {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        set.add("抖音");
        set.add("快手");
        set.add("小红书");

        // 把set集合 转换成流
        Stream<String> stream = set.stream();
        // map集合是间接方式
        Map<String,String> map = new HashMap<>();
        map.put("小头儿子","大头爸爸");
        map.put("奥特曼","小怪兽");
        map.put("海尔","兄弟");

        Set<Map.Entry<String, String>> entries = map.entrySet();

        Stream<Map.Entry<String, String>> stream1 = entries.stream();

        //数组
        Integer[] arr = {1,3,5,6};
        Stream<Integer> stream2 = Arrays.stream(arr);

        // 如果你有一堆数据想要收集好流中
        Stream<Integer> arr1 = Stream.of(arr);

        Stream<String> a = Stream.of("a", "b", "c");


    }
}

3.4 Stream 的 filter 方法

1641979859672

java
/*
    java.util.stream.Stream<T>接口: 我们已经可以获取Stream接口的实现类对象
    抽象方法:
        public abstract Stream<T> filter(Predicate<T> p):
            按照方法参数p指定的条件对Stream流对象中的元素进行过滤,返回一个新的Stream流对象
            参数:
                Predicate<T> p: 判断型型接口,传递匿名内部类对象,lambda表达式

        java.util.function.Predicate<T>接口:
        	判断型接口 功能: 根据T类型的数据获取boolean类型的结果
        抽象方法:
            public abstract boolean test(T t): 根据方法参数T类型的数据t,返回一个boolean类型的结果
 */
package com.itheima.stream;

import java.util.function.Predicate;
import java.util.stream.Stream;

public class Stream01Filter {

    public static void main(String[] args) {
        //把数据收集到流中
        Stream<String> stream = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃", "爷爷", "穿山甲", "蛇精", "蝎子精");

        /*
           如果我们想要对 流中的数据进行 过滤筛选
             就推荐使用
                filter功能

              Stream<String>  filter(Predicate<String> p )
                  根据某个条件进行过滤  返回过滤后的流
                  方法里面要的是 一个接口 这个接口 是函数式接口
                           只有一个  boolean test(String ) 抽象方法

         */
         //匿名内部类
//        Stream<String> stringStream = stream.filter(new Predicate<String>() {
//            @Override
//            public boolean test(String s) {
//                return s.contains("娃");
//            }
//        });
//        stream.filter()//可以选择匿名内部类  还可以使用新学的lambda表达式
//        Stream<String> stringStream2 = stream.filter((String s) -> {return s.contains("娃"); });
        Stream<String> stringStream2 = stream.filter( s ->  s.contains("娃"));
        //返回值  ☞的是 到了下一流程

        //终结方法 用完 流中没有数据
//        long count = stream.count();
//
//        System.out.println(count);


        // forEach也是终结方法
        stringStream2.forEach(s->{
            System.out.println(s);
        });
    }
}

3.5 Stream 的 limit 和 skip 方法

1628582049530

java
package com.itheima.stream;

import java.util.stream.Stream;

public class Stream02Limit {
    /*
      limit n 限制的意思
         限制长度   取前n个
     */
    public static void main(String[] args) {
        //把数据收集到流中
        Stream<String> stream = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃", "爷爷", "穿山甲", "蛇精", "蝎子精");
        // 疫情严重 只允许 5个人来上课
        // 说白了 限制5个人来  说白了前五个来
        Stream<String> stream2 = stream.limit(5);

//        System.out.println(stream2.count());

        stream2.forEach(s-> System.out.println(s));
    }
}
java
package com.itheima.stream;

import java.util.stream.Stream;


public class Stream02Skip {
   /*
     skip n 跳过n个 从n+1
    */

    public static void main(String[] args) {
        //把数据收集到流中
        Stream<String> stream = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃", "爷爷", "穿山甲", "蛇精", "蝎子精");
        // 第二天 跳过前五个
        Stream<String> stream1 = stream.skip(5);

        stream1.forEach(s-> System.out.println(s));
    }
}

3.6 Stream 的 concat 方法

1628582251677

java
/*
    java.util.stream.Stream<T>接口: 我们已经可以获取Stream接口的实现类对象
    静态方法: 由接口名称调用
        public static <T> Stream<T> concat(Stream<T> a, Stream<T> b):
            把方法参数指定的两个Stream流对象合并成一个Stream流对象返回
 */
package com.itheima.stream;

import java.util.stream.Stream;

public class Stream03Concat {

    public static void main(String[] args) {
        Stream<String> a = Stream.of("大娃", "二娃", "三娃", "四娃", "五娃", "六娃", "七娃");
        Stream<String> b = Stream.of( "爷爷", "穿山甲", "蛇精", "蝎子精");

        //两条独立的流 合并成一个流
        Stream<String> concat = Stream.concat(b, a);
       //
        concat.forEach(s-> System.out.println(s));

    }
}

3.7 distinct 去重方法

1641979871023

java
package com.itheima.stream;

import java.util.stream.Stream;

public class Stream04distinct {

    public static void main(String[] args) {
        Stream<String> a = Stream.of("大娃", "二娃", "三娃", "四娃", "三娃", "二娃", "七娃");

        //去重
        Stream<String> stream2 = a.distinct();

        stream2.forEach(s-> System.out.println(s));

    }
}

3.8 Stream 的 forEach count 方法

1641979939402

java
void forEach​(Consumer action):对此流的每个元素执行操作
 遍历的意思,这句话的意思是把流中的每个元素,拿出来进行消费!!
 拿出来了还能再拿出来吗?

 因为这是终结方法,只能使用一次。
java
package com.itheima.stream;

import java.util.stream.Stream;

public class Stream05ForeachCount {

    public static void main(String[] args) {
        Stream<String> a = Stream.of("大娃", "二娃", "三娃", "四娃", "三娃", "二娃", "七娃");

         //count计数  终结方法  执行完毕 流中就无数据了
//        long count = a.count();
//        System.out.println(count);

//        Stream<String> skip = a.skip(1);  终结方法一旦调用 说明流关闭  流中没有数据了

//        a.forEach((String s)->{
//            System.out.println(s);
//        });

        a.forEach( s->System.out.println(s));
    }
}

3.9 收集功能

1628582831589

java
package com.itheima.stream;

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Stream06ShouJi {

    public static void main(String[] args) {

        Stream<String> stream1 = Stream.of("迪丽热巴", "古力娜扎", "马尔扎哈", "达拉崩吧","马尔扎哈");

        //把stream1 收集到数组中
//        Object[] objects = stream1.toArray();
//        System.out.println(Arrays.toString(objects));

        //把 stream1 收集到单列集合 List 集合 set集合
//        List<String> list = stream1.collect(Collectors.toList());
//
//        System.out.println(list);

        Set<String> set = stream1.collect(Collectors.toSet());
        System.out.println(set);

    }
}

3.10 传统模式完成案例

java
/*
    Stream流综合练习
    要求:
        1. 第一个队伍只要名字为3个字的成员姓名;
        2. 第一个队伍筛选之后只要前3个人;
        3. 第二个队伍只要姓张的成员姓名;
        4. 第二个队伍筛选之后不要前2个人;
        5. 将两个队伍合并为一个队伍;
        6. 打印整个队伍的姓名信息。

    按照传统操作集合的方式
 */
public class Demo02StreamTest {
    public static void main(String[] args) {
        List<String> o = new ArrayList<>();
        o.add("迪丽热巴");
        o.add("宋远桥");
        o.add("苏星河");
        o.add("老子");
        o.add("庄子");
        o.add("孙子");
        o.add("洪七公");

        //1. 第一个队伍只要名字为3个字的成员姓名;
        List<String> oSaZi = new ArrayList<>();
        for (String name : o) {
            if (name.length() == 3) {
                oSaZi.add(name);
            }
        }

        //2. 第一个队伍筛选之后只要前3个人;
        List<String> oSaZiLimit3 = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            oSaZiLimit3.add(oSaZi.get(i));
        }

        List<String> t = new ArrayList<>();
        t.add("古力娜扎");
        t.add("张无忌");
        t.add("张三丰");
        t.add("赵丽颖");
        t.add("张二狗");
        t.add("张天爱");
        t.add("张三");

        //3. 第二个队伍只要姓张的成员姓名;
        List<String> tZhang = new ArrayList<>();
        for (String name : t) {
            if (name.startsWith("张")) {
                tZhang.add(name);
            }
        }

        //4. 第二个队伍筛选之后不要前2个人;

        List<String> tZhangSkip2 = new ArrayList<>();
        for (int i = 2; i < tZhang.size(); i++) {
            tZhangSkip2.add(tZhang.get(i));
        }

        //5. 将两个队伍合并为一个队伍;
        List<String> ot = new ArrayList<>();
        ot.addAll(oSaZiLimit3);//把方法参数集合对象中的元素添加到ot中
        ot.addAll(tZhangSkip2);//把方法参数集合对象中的元素添加到ot中

        //6. 打印整个队伍的姓名信息。
        for (String name : ot) {
            System.out.println(name);
        }
    }
}

3.11 Stream 流的方式完成案例

java
package com.itheima.stream;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class Test {
   /*
    Stream流综合练习
    要求:
        1. 第一个队伍只要名字为3个字的成员姓名;
        2. 第一个队伍筛选之后只要前3个人;
        3. 第二个队伍只要姓张的成员姓名;
        4. 第二个队伍筛选之后不要前2个人;
        5. 将两个队伍合并为一个队伍;
        6. 打印整个队伍的姓名信息。

    按照传统操作集合的方式

    */
    public static void main(String[] args) {
        //队伍1
        List<String> o = new ArrayList<>();
        o.add("迪丽热巴");
        o.add("宋远桥");
        o.add("苏星河");
        o.add("老子");
        o.add("庄子");
        o.add("孙子");
        o.add("洪七公");

        // 获取流 o-stream流  推荐链式编程
        Stream<String> one = o.stream().filter(name -> name.length() == 3).limit(3);
        //队伍2
        List<String> t = new ArrayList<>();
        t.add("古力娜扎");
        t.add("张无忌");
        t.add("张三丰");
        t.add("赵丽颖");
        t.add("张二狗");
        t.add("张天爱");
        t.add("张三");
        Stream<String> two = t.stream().filter(name -> name.startsWith("张")).skip(2);

        //两只队伍合并
        Stream<String> newTeam = Stream.concat(one, two);

        newTeam.forEach(s-> System.out.println(s));

    }
}

Released under the MIT License.