JavaSE - 12 JDK8新特性

发布于:2023-01-04 ⋅ 阅读:(302) ⋅ 点赞:(0)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


1.函数式编程

  • 只包含一个抽象方法的接口,称为函数式接口

  • 你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式 抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽 象方法上进行声明)。

  • 我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检 查它是否是一个函数式接口。同时 javadoc 也会包含一条声明,说明这个 接口是一个函数式接口。

  • 在java.util.function包下定义了Java 8 的丰富的函数式接口

  • 函数式编程思想:

    1. 对面向对象思想的简化
    2. 忽略对象的创建,和对象功能的声明,重点关注 此行为是如何实现的(方法体)
  • 已经学过的函数式接口:

    Runnable接口 : 线程对象的任务接口 -> void run();
    Comparable<E>接口 : 绑定比较器接口 -> int compareTo(E o)
    Comparator<E>接口 : 独立比较器接口 -> int compare(E o1,E o2)
    Callable<V>接口 : 线程对象的有结果的任务接口 -> E call()
    FileFilter接口 : 文件过滤器接口 -> boolean accept(File fileName)
    

2.Lambda表达式

概述: Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以 传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更 灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了 提升。实质上是对匿名内部类在作用于函数式接口时的格式简化也可称为 箭头函数

使用场景: 只能作用在函数式接口上,对匿名内部类的简化书写格式。

格式:

(参数列表) -> {
    方法体;
}; 

Lambda表达式简化条件:

  1. 如果重写方法内的代码,有且仅有一句,可以省略 包裹方法体的大括号,语句结尾的分号,(如果方法内有return 也可以省略return) 要省略都省略,不能只省略其中一个 。
  2. Lambda表达式重写方法的形参列表中的形参类型都可以省略 。
  3. 如果重写方法的形参 有且仅有一个 那么可以省略形参的小括号 。
  4. 形参名可以修改,方法体内的形参使用也要改名字 。//一般不弄

代码示例:

public class Demo01 {
    public static void main(String[] args) {
        // 1.无返回值类型,无参数列表
        // a、使用匿名对象,实例化实现类
        InterA interA_a = new InterA() {
            @Override
            public void method() {
                System.out.println("无返回值类型,无参数列表--->匿名对象");
            }
        };
        interA_a.method();

        // b、使用Lambda表达式替换匿名对象实例化实现类
        InterA interA_b = () -> System.out.println("无返回值类型,无参数列表--->Lambda表达式");
        interA_b.method();

        System.out.println("----------------------------");

        //2. 无返回值类型,有参数列表
        // a、使用匿名对象,实例化实现类
        InterB interB_a = new InterB() {
            @Override
            public void method(String str) {
                System.out.println(str);
            }
        };
        interB_a.method("返回值类型,有参数列表--->匿名对象");

        // b、使用Lambda表达式替换匿名对象实例化实现类
        InterB interB_b = str -> System.out.println(str);
        interB_b.method("返回值类型,有参数列表--->Lambda表达式");

        System.out.println("----------------------------");

        //3. 有返回值类型,无参数列表
        // a、使用匿名对象,实例化实现类
        InterC interC_a = new InterC() {
            @Override
            public String method() {
                return "有返回值类型,无参数列表--->匿名对象";
            }
        };
        System.out.println("interC_a.method() = " + interC_a.method());

        // b、使用Lambda表达式替换匿名对象实例化实现类
        InterC interC_b = () -> "有返回值类型,无参数列表--->Lambda表达式";
        System.out.println("interC_b.method() = " + interC_b.method());

        System.out.println("----------------------------");

        //4. 有返回值类型,有形参
        // a、使用匿名对象,实例化实现类
        InterD interD_a = new InterD() {
            @Override
            public String method(String str) {
                return str;
            }
        };
        System.out.println("interD_a.method() = " + interD_a.method("有返回值类型,有参数列表--->匿名对象"));

        // b、使用Lambda表达式替换匿名对象实例化实现类
        InterD interD_b = (str) -> str;
        System.out.println("interD_b.method() = " + interD_b.method("有返回值类型,有参数列表--->Lambda表达式"));

        System.out.println("----------------------------");

    }
}

// 无返回值类型,无参数列表
@FunctionalInterface
interface InterA{
    public abstract void method();
}

// 无返回值类型,有参数列表
@FunctionalInterface
interface InterB{
    public abstract void method(String str);
}

// 有返回值类型,无参数列表
@FunctionalInterface
interface InterC{
    public abstract String method();
}

// 有返回值类型,有形参
@FunctionalInterface
interface InterD{
    public abstract String method(String str);
}

3.方法引用(Method References)了解

3.1 概述

  • 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!

  • 方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就 是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向 一个方法,可以认为是Lambda表达式的一个语法糖。

  • 要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的 方法的参数列表和返回值类型保持一致!

  • 实质:方法的引用实质式对Lambda表达式的简化

  • 使用条件:

    1. 必须满足Lambda表达式的前置条件(必须是函数式接口)
    2. 必须要求重写方法内方法体有且仅有一句代码 --> 严苛
    3. 必须要求重写方法内方法体的这句代码: -> 严苛至极
    	a. 对象调方法
    	b. 类名调静态方法
    	c. 创建对象
    	d. 创建数组
    4. 形参要在以上功能中使用//使用条件
    
  • 标志:::

  • Lambda表达式是可以简化函数式接口的变量与形参赋值的语法。而方法引用和构造器引用是为了简化 Lambda表达式的。当Lambda表达式满足一些特殊的情况时,还可以再简化:

3.2 使用格式

方法的引用:

1)对象调方法 --> 对象名::实例方法 
(2)类名调用静态方法 --> 类名::静态方法
 注意事项 :
	1.::称为方法引用操作符
	2.Lambda表达式的形参列表,全部在Lambda体中使用上了,要么是作为调用方法的对象,要么是作为方法的实参。
	3.在整个Lambda体中没有额外的数据。

构造器引用:

(1)当Lambda表达式是创建一个对象,并且满足Lambda表达式形参,正好是给创建这个对象的构造 器的实参列表。

(2) 当Lambda表达式是创建一个数组对象,并且满足Lambda表达式形参,正好是给创建这个数组 对象的长度

类名::new
数组类型名::new

代码演示:

public class Demo01 {
    public static void main(String[] args) {
        // 匿名对象写法
        InterA interA = new InterA() {
            @Override
            public void print(String str) {
                System.out.println(str);
            }
        };
        interA.print("只展示一次匿名对象写法");
        System.out.println("---------------------------------");

        /**
         * 方法引用的条件
         * 基于Lambda做的简化,要求重写方法内有且仅有一句代码且这句代码是
         * 要么对象调方法
         * 要么类名调用静态方法
         * 要么是创建对象
         * 要么是创建一个数组
         */

        // 1.InterA 对象的调用 对象名::方法名称
        InterA interA1 = System.out :: println;
        interA1.print("类名::方法名称");

        // 2.InterB 静态方法的调用 类名::方法名
        InterB interB = Integer :: parseInt;
        interB.change("123");

        // 3.InterC 构造使用 对象名::new
        InterC interC = Date :: new;
        interC.get();

        //4.InterD 数组 类型[] :: new
        InterD interD = int[] :: new ;
        interD.get(10);

    }


}
@FunctionalInterface
interface InterA{
    public abstract void print(String str);
}

@FunctionalInterface
interface InterB{
    public abstract int change(String str);
}

@FunctionalInterface
interface InterC{
    public abstract Date get();
}

@FunctionalInterface
interface InterD{
    public abstract int[] get(int length);
}

4.Stream API

4.1 概述

  • Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则 是 Stream API。

  • Stream API ( java.util.stream) 把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程 序员的生产力,让程序员写出高效率、干净、简洁的代码。

  • Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进 行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。 使用 Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。 也可以使用 Stream API 来并行执行操作。简言之,Stream API 提供了一种 高效且易于使用的处理数据的方式。

  • 为什么要使用Stream API

    • 实际开发中,项目中多数数据源都来自于Mysql,Oracle等。但现在数 据源可以更多了,有MongDB,Radis等,而这些NoSQL的数据就需要 Java层面去处理。
    • Stream 和 Collection 集合的区别: Collection 是一种静态的内存数据 结构,而 Stream 是有关计算的。前者是主要面向内存,存储在内存中, 后者主要是面向 CPU,通过 CPU 实现计算。
  • Stream 的操作三个步骤

    • 创建 Stream : 一个数据源(如:集合、数组),获取一个流
    • 中间操作 : 一个中间操作链,对数据源的数据进行处理
    • 终止操作(终端操作) : 一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用
  • Stream 操作流程图

在这里插入图片描述

4.2 创建Stream流

常用的方法:

-- 1.单集合创建Streamdefault Stream<E> stream() : 返回以此集合作为源的顺序 StreamStream<E> 流对象 = 集合.stream();

-- 2.双列集合创建Stream对象,双列集合不能直接创建Stream,而是要转换成单列集合在转Stream
    a. 先获取键集 : Set<K> keySet() , 键集进流
	b. 先获取值集 : Collection<V> values() , 值集进流
	c. 先获取键值对集合 : Set<Map.Entry<K,V>> entrySet() ,键值对集合进流 -> 推荐

-- 3.数组创建Stream对象(Arrays工具类)
   static <T>Stream stream(<T>[] array) : 返回顺序<T>Stream与指定的数组作为源  
   <T>Stream 流对象 = Arrays.stream(<T>[] array);
    
-- 4. 一组同类型的数据
   static <T> Stream<T> of(T... values) : 返回其元素是指定值的顺序排序流。 
   Stream<T> 流对象 = Stream.of(一组相同数据类型的数据); 

代码演示:

public class Demo01 {
    public static void main(String[] args) {
        listStream();
        System.out.println("---------------------");

        mapStream();
        System.out.println("---------------------");

        arrayStream();
        System.out.println("----------------------");

        dataStream();
    }

    /**
     *  1.单集合创建Stream流
     *  default Stream<E> stream() : 返回以此集合作为源的顺序 Stream 。
     *  Stream<E> 流对象 = 集合.stream();
     */
    public static void listStream(){
        // 1.创建集合
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"aaa","bbb","ccc");

        // 2.创建流对象
        Stream<String> stream = list.stream();

        // 3.查看Stream
        stream.forEach(System.out :: println);
    }

    /**
     * 2.双列集合创建Stream对象,双列集合不能直接创建Stream,而是要转换成单列集合在转Stream
     * a. 先获取键集 : Set<K> keySet() , 键集进流
     * b. 先获取值集 : Collection<V> values() , 值集进流
     * c. 先获取键值对集合 : Set<Map.Entry<K,V>> entrySet() ,键值对集合进流 -> 推荐
     */
    public static void mapStream(){
        HashMap<String, Integer> map = new HashMap<>();
        map.put("aaa",1);
        map.put("bbb",2);
        map.put("ccc",3);

        // 将双列集合转成单列集合
        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        // 创建Stream对象
        Stream<Map.Entry<String, Integer>> stream = entries.stream();
        // 输出Stream流
        stream.forEach(System.out :: println);
    }

    /**
     * 3.数组创建Stream对象(Arrays工具类)
     * static <T>Stream stream(<T>[] array) : 返回顺序<T>Stream与指定的数组作为源
     *  <T>Stream 流对象 = Arrays.stream(<T>[] array);
     */
    public static void arrayStream(){
        int[] arr = {1,2,3,4,5,6,7,8};

        // 创建Stream流对象
        IntStream stream = Arrays.stream(arr);

        // 输出流
        stream.forEach(System.out :: println);
    }

    /**
     * 4. 一组同类型的数据
     * static <T> Stream<T> of(T... values) : 返回其元素是指定值的顺序排序流。
     * Stream<T> 流对象 = Stream.of(一组相同数据类型的数据);
     */
    public static void dataStream(){
        // 创建Stream流
        Stream<Double> doubleStream = Stream.of(1.1, 1.2, 1.3);

        // 输出Stream
        doubleStream.forEach(System.out::println);
    }
}

4.3 Stream流中间操作方法

常用的方法:

-- 过滤操作
   Stream<T> filter(Predicate<? super T> predicate) : 返回由与此给定谓词匹配的此流的元素组成的流。
   // 该方法实现过滤的操作,过滤操作是由Predicate接口中test方法实现的。所以要重写test方法,在方法中写过滤操作
 
-- 截取操作
   Stream<T> limit(long maxSize) : 返回由此流的元素组成的流,截短长度不能超过 maxSize 。  

-- 跳过操作
   Stream<T> skip(long n) : 在丢弃流的第一个 n元素后,返回由该流的 n元素组成的流。
  
-- 去重操作
   Stream<T> distinct() : 返回由该流的不同元素(根据 Object.equals(Object) )组成的流。  
 
-- 排序操作
   Stream<T> sorted() : 返回由此流的元素组成的流,根据自然顺序排序。 
   Stream<T> sorted(Comparator<? super T> comparator) : 返回由该流的元素组成的流,根据提供的 Comparator进行排序。  

-- 合并操作
   static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) : 创建一个懒惰连接的流,其元素是第一个流的所有元素,后跟第二个流的所有元素 
 
-- 转换操作
   <R> Stream<R> map(Function<? super T,? extends R> mapper) : 返回由给定函数应用于此流的元素的结果组成的流。 

代码演示:

public class Demo02 {
    public static void main(String[] args) {
        filterTest();
        System.out.println("------------------------");
        limitTest();
        System.out.println("------------------------");
        skipTest();
        System.out.println("------------------------");
        distinctTest();
        System.out.println("------------------------");
        sortTest();
        System.out.println("------------------------");
        concatTest();
        System.out.println("------------------------");
        mapTest();
        System.out.println("------------------------");
    }


    /**
     * 过滤操作
     * Stream<T> filter(Predicate<? super T> predicate) : 返回由与此给定谓词匹配的此流的元素组成的流。
     * 该方法实现过滤的操作,过滤操作是由Predicate接口中test方法实现的。所以要重写test方法,在方法中写过滤操作
     */
    public static void filterTest(){
        // 创建流Stream对象
        Stream<String> stream = Stream.of( "张三丰",  "李四", "王五","张思", "赵六","张三");

        // 获取所有姓张的名字
        /*
        Stream<String> newStream = stream.filter(new Predicate<String>() {
            @Override
            public boolean test(String name) {
                return name.startsWith("张");
            }
        });
        */
        Stream<String> newStream = stream.filter(name -> name.startsWith("张"));

        // 输出流
        newStream.forEach(System.out :: println);
    }

    /**
     *  截取操作
     *   Stream<T> limit(long maxSize) : 返回由此流的元素组成的流,截短长度不能超过 maxSize 。
     */
    public static void limitTest(){
        // 创建流Stream对象
        Stream<Integer> stream = Stream.of(1,2,3,4,5,6,7,8,9,10);

        // 保留5之前的数字
        Stream<Integer> limit = stream.limit(5);

        // 输出流
        limit.forEach(System.out :: println);
    }

    /**
     * 跳过操作
     * Stream<T> skip(long n) : 在丢弃流的第一个 n元素后,返回由该流的 n元素组成的流。
     */
    public static void skipTest(){
        // 创建流Stream对象
        Stream<Integer> stream = Stream.of(1,2,3,4,5,6,7,8,9,10);

        // 跳过4之前的数
        Stream<Integer> skip = stream.skip(4);

        skip.forEach(System.out :: println);
    }

    /**
     * 去重操作
     *  Stream<T> distinct() : 返回由该流的不同元素(根据 Object.equals(Object) )组成的流。
     */
    public static void distinctTest(){
        // 创建流Stream对象
        Stream<Integer> stream = Stream.of(1,1,3,2,5,5,8,8,9,10);

        // 去除重复的数字
        Stream<Integer> distinct = stream.distinct();

        distinct.forEach(System.out :: println);
    }

    /**
     * 排序操作
     *    Stream<T> sorted() : 返回由此流的元素组成的流,根据自然顺序排序。
     *    Stream<T> sorted(Comparator<? super T> comparator) : 返回由该流的元素组成的流,根据提供的 Comparator进行排序。
     */
    public static void sortTest(){
        // 创建流Stream对象
        Stream<Integer> stream = Stream.of(1,4,3,2,6,5,8,7,9,10);

        // 排序
        Stream<Integer> sorted = stream.sorted((o1,o2) -> o1 - o2 );

        sorted.forEach(System.out :: println);

    }

    /**
     * 合并操作
     *    static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) : 创建一个懒惰连接的流,其元素是第一个流的所有元素,后跟第二个流的所有元素
     */
    public static void concatTest(){
        Stream<Integer> stream1 = Stream.of(1,4,3,2);
        Stream<Integer> stream2 = Stream.of(5,8,7,9,10);
        Stream<Integer> concat = Stream.concat(stream1, stream2);

        concat.forEach(System.out :: println);
    }

    /**
     * 转换操作
     *    <R> Stream<R> map(Function<? super T,? extends R> mapper) : 返回由给定函数应用于此流的元素的结果组成的流。
     */
    public static void mapTest(){
        Stream<Integer> stream = Stream.of(1,4,3,2);
        Stream<String> newStream = stream.map(Object::toString);

        newStream.forEach(System.out :: println);
    }
}

4.4 Stream流的终止操作

常用的方法:

1.遍历终结
	void forEach(Consumer<? super T> action) : 对此流的每个元素执行操作 
  	//foreach方法可以获取流中的所有数据,拿到元素后如何使用由重写的accept方法决定

2.统计终结
  	long count() : 返回此流中的元素数。  

3.收集终结
    <R,A> R collect(Collector<? super T,A,R> collector)
		要调用collect方法需要传递Collector的实现类对象,但是Collector实现类对象自己不会写;
		需要借助工具类 : Collectors -> 可以快速的生成Collector对象
	
   Collectors工具类中的方法 :
        static <T> Collector<T,?,List<T>> toList() : 把流中元素收集成List集合
        static <T> Collector<T,?,Set<T>> toSet() : 把流中元素收集成Set集合
        //Set集合中的元素可以去重 -> 去重原理 : hashCode 和 equals
        static <T,K,U> Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K>keyMapper, Function<? super T,? extends U> valueMapper)
        简化 :
        static Collector<T,?,Map<K,U>> toMap(Function<T,K> key, Function<T,U> value)

代码演示:

public class Demo03 {
    public static void main(String[] args) {
        forEachTest();
        System.out.println("---------------");
        countTest();
        System.out.println("---------------");
        collectTest();
        System.out.println("---------------");
    }
    /**
     * 1.遍历终结
     * 	void forEach(Consumer<? super T> action) : 对此流的每个元素执行操作
     *  //foreach方法可以获取流中的所有数据,拿到元素后如何使用由重写的accept方法决定
     */
    public static void forEachTest(){
        // 创建流Stream对象
        Stream<String> stream = Stream.of( "张三丰",  "李四", "王五","张思", "赵六","张三");
        stream.forEach(System.out :: println);
    }

    /**
     * 2.统计终结
     * long count() : 返回此流中的元素数。
     */
    public static void countTest(){
        // 创建流Stream对象
        Stream<String> stream = Stream.of( "张三丰",  "李四", "王五","张思", "赵六","张三");
        // 统计个数
        long count = stream.count();
        System.out.println("count = " + count);
    }

    /**
     * 3.收集终结
     *     <R,A> R collect(Collector<? super T,A,R> collector)
     * 		要调用collect方法需要传递Collector的实现类对象,但是Collector实现类对象自己不会写;
     * 		需要借助工具类 : Collectors -> 可以快速的生成Collector对象
     * 	 Collectors工具类中的方法 :
     *         static <T> Collector<T,?,List<T>> toList() : 把流中元素收集成List集合
     *         static <T> Collector<T,?,Set<T>> toSet() : 把流中元素收集成Set集合
     *         //Set集合中的元素可以去重 -> 去重原理 : hashCode 和 equals
     *         static <T,K,U> Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K>keyMapper, Function<? super T,? extends U> valueMapper)
     *         简化 :
     *         static Collector<T,?,Map<K,U>> toMap(Function<T,K> key, Function<T,U> value)
     */
    public static void collectTest(){
        // 创建流Stream对象
        Stream<String> stream = Stream.of( "张三丰",  "李四", "王五","张思", "赵六","张三");

        List<String> collect = stream.collect(Collectors.toList());

        for (String s : collect) {
            System.out.println("s = " + s);
        }
    }
}

4.5 综合案例

案例描述:

现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作

  1. 男演员只要名字为3个字的前三人
  2. 女演员只要姓林的,并且不要第一个
  3. 把过滤后的男演员姓名和女演员姓名合并到一起
  4. 把上一步操作后的元素作为构造方法的参数创建演员对象 -> String 转换 Actor
  5. 把转换后的流收集成List集合并遍历List集合
public class Actor implements Serializable {
    private static final long serialVersionUID = 5215563480733681684L;
    private String name;
    public Actor() {
    }
    public Actor(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Actor actor = (Actor) o;
        return Objects.equals(name, actor.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
    @Override
    public String toString() {
        return "Actor{" +
                "name='" + name + '\'' +
                '}';
    }
}

代码演示:

public class Demo01 {
    public static void main(String[] args) {
        //创建集合
        ArrayList<String> manList = new ArrayList<String>();
        manList.add("周润发");
        manList.add("成龙");
        manList.add("刘德华");
        manList.add("吴京");
        manList.add("周星驰");
        manList.add("李连杰");

        ArrayList<String> womanList = new ArrayList<String>();
        womanList.add("林心如");
        womanList.add("张曼玉");
        womanList.add("林青霞");
        womanList.add("柳岩");
        womanList.add("林志玲");
        womanList.add("王祖贤");
        // 创建Stream流对象
        Stream<String> manStream1 = manList.stream();
        Stream<String> womanStream1 = womanList.stream();

        // 1.男演员只要名字为3个字的前三人
        Stream<String> manStream2 = manStream1.filter( name-> name.length() == 3 );
        Stream<String> manStream3 = manStream2.limit(3);

        // 2. 女演员只要姓林的,并且不要第一个
        Stream<String> womanStream2 = womanStream1.filter(name -> name.startsWith("林"));
        Stream<String> womanStream3 = womanStream2.skip(1);

        // 3.把过滤后的男演员姓名和女演员姓名合并到一起
        Stream<String> concatStream = Stream.concat(manStream3, womanStream3);

        // 4.把上一步操作后的元素作为构造方法的参数创建演员对象 -> String 转换 Actor
        Stream<Actor> actorStream = concatStream.map( Actor :: new);

        // 5.把转换后的流收集成List集合并遍历List集合
        List<Actor> collectList = actorStream.collect(Collectors.toList());

        System.out.println("collectList = " + collectList);
    }
}

优化上述代码:

public class Demo02 {
    public static void main(String[] args) {
        //创建集合
        ArrayList<String> manList = new ArrayList<String>();
        manList.add("周润发");
        manList.add("成龙");
        manList.add("刘德华");
        manList.add("吴京");
        manList.add("周星驰");
        manList.add("李连杰");

        ArrayList<String> womanList = new ArrayList<String>();
        womanList.add("林心如");
        womanList.add("张曼玉");
        womanList.add("林青霞");
        womanList.add("柳岩");
        womanList.add("林志玲");
        womanList.add("王祖贤");

        List<Actor> collectList =
                // 3.把过滤后的男演员姓名和女演员姓名合并到一起
                Stream.concat(
                        // 1.男演员只要名字为3个字的前三人
                        manList.stream().filter( name-> name.length() == 3 ),
                        // 2. 女演员只要姓林的,并且不要第一个
                        womanList.stream().filter(name -> name.startsWith("林")).skip(1))
                        // 4.把上一步操作后的元素作为构造方法的参数创建演员对象 -> String 转换 Actor
                        .map( Actor :: new)
                        // 5.把转换后的流收集成List集合并遍历List集合
                        .collect(Collectors.toList());
        System.out.println("collectList = " + collectList);
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到