当前位置: 代码迷 >> 综合 >> Java8新特性 Lambda、Stream、Optional实现原理
  详细解决方案

Java8新特性 Lambda、Stream、Optional实现原理

热度:67   发布时间:2023-10-31 13:28:24.0

Java8新特性 Lambda、Stream、Optional实现原理

  • 一、接口中默认方法修饰为普通方法
  • 二、Lambda表达式
    • 2.1、什么是Lambda表达式
    • 2.2、为什么要使用Lambda表达式
    • 2.3、Lambda表达式的规范
    • 2.4、函数接口定义
    • 2.5、Java系统内置那些函数接口
      • 2.5.1、消费型接口:
      • 2.5.2、供给型接口
      • 2.5.3、函数型接口
      • 2.5.4、断言型接口
    • 2.6、Lambda基础语法
      • 2.6.1、无参方法调用
      • 2.6.2、带参数和返回值
    • 2.7、方法引入
      • 2.7.1、什么是方法引入
      • 2.7.2、方法引入
        • 2.7.2.1、方法引入规则
        • 2.7.2.2、静态方法引入
        • 2.7.2.3、对象方法引入
        • 2.7.2.4、实例方法引入
        • 2.7.2.5、构造函数引入
    • 2.8、Lambda实战案例
      • 2.8.1、Foreach
      • 2.8.2、Lambda集合排序
      • 2.8.3、线程调用
  • 三、Stream流
    • 3.1、什么是Stream流
    • 3.2、Stream创建方式
    • 3.3、Stream将list转换为Set
    • 3.4、Stream将list转换为Map
    • 3.5、Stream将Reduce 求和
    • 3.6、StreamMax和Min
    • 3.7、StreamMatch 匹配
    • 3.8、StreamFor循环
    • 3.9、Stream过滤器
    • 3.10、Stream排序 sorted
    • 3.11、Stream limit和skip
    • 3.12、并行流与串行流区别
  • 四、JDK8 Optional
    • 4.1、判断参数是否为空
    • 4.2、参数为空可以设定默认值
    • 4.3、参数实现过滤
    • 4.4、与Lambda表达式结合使用,优化代码
      • 4.4.1、优化方案1
      • 4.4.2、优化方案2
      • 4.4.3、优化方案3

一、接口中默认方法修饰为普通方法

在jdk8之前,interface之中可以定义变量和方法,变量必须是public、static、final的,方法必须是public、abstract的,由于这些修饰符都是默认的。

接口定义方法:public 抽象方法 需要子类实现

接口定义变量:public、static、final

在JDK 1.8开始 支持使用static和default 修饰 可以写方法体,不需要子类重写。

方法:

  • 普通方法 可以有方法体
  • 抽象方法 没有方法体需要子类实现 重写。

二、Lambda表达式

2.1、什么是Lambda表达式

Lambda 好处:

  • 简化我们匿名内部类的调用。
  • Lambda + 方法引入 代码变得更加精简。
  • Lambda 表达式(lambda expression)是一个匿名函数,简化我们调用匿名函数的过程。

2.2、为什么要使用Lambda表达式

可以非常简洁的形式调用我们的匿名函数接口。
OrderService

public interface OrderService {
    void addOrder();
}

OrderServiceImpl

public class OrderServiceImpl implements OrderService {
    @Overridepublic void addOrder() {
    System.out.println("添加订单");}
}

Test01

public static void main(String[] args) {
    //1.使用new的实现类的形式调用接口OrderService orderService = new OrderServiceImpl();orderService.addOrder();//2.使用匿名内部接口调用new OrderService() {
    @Overridepublic void addOrder() {
    System.out.println("使用匿名内部类的形式调用接口");}}.addOrder();// 3.使用lambda调用接口OrderService orderService2 = () -> System.out.println("使用lambda调用接口");orderService2.addOrder();}

2.3、Lambda表达式的规范

使用Lambda表达式 依赖于函数接口

  1. 在接口中只能够允许有一个抽象方法
  2. 在函数接口中定义object类中方法
  3. 使用默认或者静态方法
  4. @FunctionalInterface 表示该接口为函数接口

Java中使用Lambda表达式的规范,必须是为函数接口

函数接口的定义:

  • 在该接口中只能存在一个抽象方法,该接口称作为函数接口

JDK中自带的函数接口:

  • java.lang.Runnable
  • java.util.concurrent.Callable
  • java.security.PrivilegedAction
  • java.util.Comparator
  • java.io.FileFilter
  • java.nio.file.PathMatcher
  • java.lang.reflect.InvocationHandler
  • java.beans.PropertyChangeListener
  • java.awt.event.ActionListener
  • javax.swing.event.ChangeListener

我们也可以使用@FunctionalInterface修饰为函数接口

2.4、函数接口定义

  1. 在接口中只能有一个抽象方法
  2. @FunctionalInterface 标记为该接口为函数接口
  3. 可以通过default 修饰为普通方法
  4. 可以定义object类中的方法
@FunctionalInterface
public interface MyFunctionalInterface {
    void add();default void get(){
    }String toString();
}

2.5、Java系统内置那些函数接口

2.5.1、消费型接口:

  • Conusmer
    void accept(T t);
  • BiConusmer<T,U>
    void accept(T t,U u);//增加一种入参类型

2.5.2、供给型接口

  • Supplier
    void get();

2.5.3、函数型接口

  • Function<T ,R>
    R apply(T t);
  • UnaryOperator
    T apply(T t);//入参与返回值类型一致
  • BiFunction <T ,U,R>
    R apply(T t,U u);//增加一个参数类型
  • BinaryOperator
    T apply(T t1,T t2);//l两个相同类型入参与同类型返回值
  • ToIntFunction//限定返回int
  • ToLongFunction//限定返回long
  • ToDoubleFunction//限定返回double
  • IntFunction//限定入参int,返回泛型R
  • LongFunction//限定入参long,返回泛型R
  • DoubleFunction//限定入参double,返回泛型R

2.5.4、断言型接口

  • Predicate
  • boolean test(T t)

2.6、Lambda基础语法

语法格式一: 无参数,无返回值。 () -> { }

Runnable runnable = () -> System.out.print("Hello Lambda");

语法格式二: 有一个参数,并且无返回值。 (x) ->{ }

Consumer<String> consumer = (x) -> System.out.print("Hello Lambda");

语法格式三: 有两个以上参数,有返回值, 并且Lambda式中有多条语句。

Comparator<Integer> comparator = (x, y) -> {
    System.out.print("Hello Lambda");return Integer.compare(x,y);
};

若Lambda体中只有一条语句,return 和 大括号都可以省略不写。

Lambda表达式参数列表的数据类型可以省略不写,因为JVM的编译器通过上下文可以推断出类型,即 “类型推断”
Lambda表达式需要“函数式接口”的支持。

函数式接口: 接口中只有一个抽象方法的接口,称为函数式接口。可以使用注解@FunctionalInterface修饰 来检查是否是函数式接口。

2.6.1、无参方法调用

AcanthopanaxInterface

public interface AcanthopanaxInterface {
    void get();
}

Test

public class Test06 {
    public static void main(String[] args) {
    AcanthopanaxInterface acanthopanaxInterface = () -> System.out.println("使用lamdba表达式调用方法");acanthopanaxInterface.get();}
}

2.6.2、带参数和返回值

YouCanInterface

public interface YouCanInterface {
    String get(int i, int j);
}

Test07

public class Test07 {
    public static void main(String[] args) {
    YouCanInterface youCanInterface = new YouCanInterface() {
    @Overridepublic String get(int i, int j) {
    return i + "----" + j;}};System.out.println(youCanInterface.get(2, 3));}
}

精简语法

public class Test07 {
    public static void main(String[] args) {
    YouCanInterface youCanInterface = (i, j) -> i + "----" + j;System.out.println(youCanInterface.get(2, 3));}
}

2.7、方法引入

2.7.1、什么是方法引入

需要结合lambda表达式能够让代码变得更加精简。

  1. 匿名内部类使用
  2. Lambda调用匿名内部类
  3. 方法引入

2.7.2、方法引入

  1. 静态方法引入: 类名::(静态)方法名称
  2. 对象方法引入 类名:: 实例方法名称
  3. 实例方法引入 new对象 对象实例::方法引入
  4. 构造函数引入 类名::new
    需要遵循一个规范:
    方法引入 方法参数列表、返回类型与函数接口参数列表与返回类型必须
    要保持一致。

Lambda: 匿名内部类使用代码简洁问题

类型 语法 对应lambda表达式
构造器引用 Class::new (args) -> new 类名(args)
静态方法引用 Class::static_method (args) -> 类名.static_method(args)
对象方法引用 Class::method (inst,args) (inst,args) -> 类名.method(args)
实例方法引用 instance::method (args) (args) -> instance.method(args)
  • 方法引用提供了非常有用的语法,可以直接引用已有的java类或对象的方法或构造器。方法引用其实也离不开Lambda表达式,

  • 与lambda联合使用 ,方法引用可以使语言的构造更加紧凑简洁,减少冗余代码。

  • 方法引用提供非常有用的语法,可以直接引用已有的java类或者对象中方法或者构造函数,

  • 方法引用需要配合Lambda表达式语法一起使用减少代码的冗余性问题。

2.7.2.1、方法引入规则

方法引入实际上就是lambda表达式中直接引入的方法。

必须遵循规范:引入的方法参数列表返回类型必须要和函数接口参数列表、返回
类型保持一致。

2.7.2.2、静态方法引入

MessageInterface

@FunctionalInterface
public interface MessageInterface {
    void get();
}

MethodReference

public class MethodReference {
    public static void main(String[] args) {
    //1.使用匿名内部类的形式 调用get方法new MessageInterface() {
    @Overridepublic void get() {
    MethodReference.getMethod();}}.get();//2.使用lambda((MessageInterface) () -> MethodReference.getMethod()).get();// 使用方法引入调用方法 必须满足:方法引入的方法必须和函数接口中的方法参数列表/返回值一定保持一致。MessageInterface messageInterface = MethodReference::getMethod;messageInterface.get();}public static void getMethod() {
    System.out.println("我是getMethod");}
}

2.7.2.3、对象方法引入

ObjectMethodService

public interface ObjectMethodService {
    String get(Test08 test08);
}

Test08

public class Test08 {
    public static void main(String[] args) {
    // 1.使用匿名内部类的形式ObjectMethodService objectMethodService = new ObjectMethodService() {
    @Overridepublic String get(Test08 test08) {
    return test08.objGet();}};System.out.println(objectMethodService.get(new Test08()));// 2.lambdaObjectMethodService objectMethodService1 = test08 -> test08.objGet();System.out.println(objectMethodService1.get(new Test08()));// 3.方法引入 在这时候我们函数接口 第一个参数传递test23 返回调用test23.objGet方法//Test08::objGet; == (test08) -> test08.objGet();ObjectMethodService objectMethodService2 = Test08::objGet;System.out.println(objectMethodService2.get(new Test08()));// 需要将string类型字符串获取长度Function<String, Integer> function2 = String::length;System.out.println(function2.apply("hello world"));}public String objGet() {
    return "hello world";}
}

2.7.2.4、实例方法引入

MessageInterface2

@FunctionalInterface
public interface MessageInterface2 {
    void get(Integer a);
}

Test09

public class Test09 {
    public static void main(String[] args) {
    //1.匿名内部类的写法Test09 test09 = new Test09();MessageInterface2 messageInterface = new MessageInterface2() {
    @Overridepublic void get(Integer a) {
    test09.get(a);}};messageInterface.get(6);//lambdaMessageInterface2 messageInterface2 = a -> test09.get(a);}public void get(Integer a) {
    System.out.println("方法引入get方法:" + a);}
}

2.7.2.5、构造函数引入

User

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;private Integer age;
}

UserInterface

public interface UserInterface {
    User getUser();
}

Test10

public class Test10 {
    public static void main(String[] args) {
    //1.匿名内部类UserInterface userInterface = new UserInterface() {
    @Overridepublic User getUser() {
    return new User();}};System.out.println(userInterface.getUser());//lambdaUserInterface userInterface2 = () -> new User();System.out.println(userInterface2.getUser());//构造函数UserInterface userInterface3 = User::new;System.out.println(userInterface3.getUser());}
}

2.8、Lambda实战案例

2.8.1、Foreach

public class Test03 {
    public static void main(String[] args) {
    List<String> list = new ArrayList<>();list.add("java");list.add("php");list.add("python");list.forEach(new Consumer<String>() {
    @Overridepublic void accept(String s) {
    System.out.println("s = " + s);}});System.out.println("=================");list.forEach((String s)-> System.out.println("s = " + s));}
}

2.8.2、Lambda集合排序

User

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;private Integer age;
}

Test04

public class Test04 {
    public static void main(String[] args) {
    List<User> userList = new ArrayList<>();userList.add(new User("zhangsan", 26));userList.add(new User("lisi", 18));userList.add(new User("wagnwu", 23));userList.sort(new Comparator<User>() {
    @Overridepublic int compare(User o1, User o2) {
    return o1.getAge() - o2.getAge();}});System.out.println("userList = " + userList);System.out.println("=========");userList.sort((User o1, User o2) -> o2.getAge() - o1.getAge());System.out.println("userList = " + userList);System.out.println("=========");}
}

2.8.3、线程调用

public class Test05 {
    public static void main(String[] args) {
    new Thread(new Runnable() {
    @Overridepublic void run() {
    System.out.println(Thread.currentThread().getName() + ",线程执行了");}}).start();new Thread(() -> System.out.println(Thread.currentThread().getName() + ",线程执行了")).start();}
}

三、Stream流

3.1、什么是Stream流

Stream 是JDK1.8 中处理集合的关键抽象概念,Lambda 和 Stream 是JDK1.8新增的函数式编程最有亮点的特性了,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用SQL执行的数据库查询。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

Stream :非常方便精简的形式遍历集合实现 过滤、排序等。

3.2、Stream创建方式

parallelStream为并行流采用多线程执行
Stream采用单线程执行
parallelStream效率比Stream要高。

public class Test11 {
    public static void main(String[] args) {
    List<User> userList = new ArrayList<>();userList.add(new User("东来佛组", 200000));userList.add(new User("如来佛组", 100000));userList.add(new User("未来佛组", 50000));userList.add(new User("斗战圣佛", 600));Stream<User> stream = userList.stream();Stream<User> userStream = userList.parallelStream();}
}

3.3、Stream将list转换为Set

Test11

public class Test11 {
    public static void main(String[] args) {
    List<User> userList = new ArrayList<>();userList.add(new User("东来佛组", 200000));userList.add(new User("如来佛组", 100000));userList.add(new User("未来佛组", 50000));userList.add(new User("斗战圣佛", 600));Stream<User> stream = userList.stream();Set<User> set = stream.collect(Collectors.toSet());System.out.println("set = " + set);}
}

3.4、Stream将list转换为Map

public class Test12 {
    public static void main(String[] args) {
    List<User> userList = new ArrayList<>();userList.add(new User("东来佛组", 200000));userList.add(new User("如来佛组", 100000));userList.add(new User("未来佛组", 50000));userList.add(new User("斗战圣佛", 600));Stream<User> stream = userList.stream();Map<String, User> collect = stream.collect(Collectors.toMap(new Function<User, String>() {
    @Overridepublic String apply(User user) {
    return user.getName();}}, new Function<User, User>() {
    @Overridepublic User apply(User user) {
    return user;}}));collect.forEach(new BiConsumer<String, User>() {
    @Overridepublic void accept(String key, User user) {
    System.out.println("key = " + key + ", value = " + user);}});}
}

3.5、Stream将Reduce 求和

public class Test13 {
    public static void main(String[] args) {
    Stream<Integer> integerStream = Stream.of(10, 20, 50, 45, 48, 56, 19);
// Optional<Integer> reduce = integerStream.reduce(new BinaryOperator<Integer>() {
    
// @Override
// public Integer apply(Integer integer, Integer integer2) {
    
// return integer + integer2;
// }
// });Optional<Integer> reduce = integerStream.reduce((integer, integer2) -> integer + integer2);System.out.println(reduce.get());List<User> userList = new ArrayList<>();userList.add(new User("东来佛组", 200000));userList.add(new User("如来佛组", 100000));userList.add(new User("未来佛组", 50000));userList.add(new User("斗战圣佛", 600));Stream<User> stream = userList.stream();
// Optional<User> reduce1 = stream.reduce(new BinaryOperator<User>() {
    
// @Override
// public User apply(User user, User user2) {
    
// user.setAge(user.getAge() + user2.getAge());
// return user;
// }
// });Optional<User> reduce1 = stream.reduce((user, user2) -> {
    user.setAge(user.getAge() + user2.getAge());return user;});System.out.println("reduce1 = " + reduce1);}
}

3.6、StreamMax和Min

public class Test14 {
    public static void main(String[] args) {
    List<User> userList = new ArrayList<>();userList.add(new User("东来佛组", 200000));userList.add(new User("如来佛组", 100000));userList.add(new User("未来佛组", 50000));userList.add(new User("斗战圣佛", 600));Stream<User> stream = userList.stream();
// Optional<User> maxUser = stream.max(new Comparator<User>() {
    
// @Override
// public int compare(User o1, User o2) {
    
// return o1.getAge() - o2.getAge();
// }
// });Optional<User> maxUser = stream.max((o1, o2) -> o1.getAge() - o2.getAge());System.out.println(maxUser.get());//流被关闭 重新打开stream = userList.stream();Optional<User> minUser = stream.min((o1, o2) -> o1.getAge() - o2.getAge());System.out.println(minUser.get());}
}

3.7、StreamMatch 匹配

anyMatch表示,判断的条件里,任意一个元素成功,返回true
allMatch表示,判断条件里的元素,所有的都是,返回true
noneMatch跟allMatch相反,判断条件里的元素,所有的都不是,返回true

public class Test15 {
    public static void main(String[] args) {
    List<User> userList = new ArrayList<>();userList.add(new User("东来佛组", 200000));userList.add(new User("如来佛组", 100000));userList.add(new User("未来佛组", 50000));userList.add(new User("斗战圣佛", 600));Stream<User> stream = userList.stream();
// boolean result = stream.noneMatch(new Predicate<User>() {
    
// @Override
// public boolean test(User user) {
    
// return user.getAge() > 99999;
// }
// });boolean result = stream.noneMatch(user -> user.getAge() > 99999);System.out.println("result = " + result);}
}

3.8、StreamFor循环

public class Test16 {
    public static void main(String[] args) {
    List<User> userList = new ArrayList<>();userList.add(new User("东来佛组", 200000));userList.add(new User("如来佛组", 100000));userList.add(new User("未来佛组", 50000));userList.add(new User("斗战圣佛", 600));Stream<User> stream = userList.stream();// stream.forEach(new Consumer<User>() {
    
// @Override
// public void accept(User user) {
    
// System.out.println("user = " + user);
// }
// });stream.forEach(user -> System.out.println("user = " + user));}
}

3.9、Stream过滤器

public class Test17 {
    public static void main(String[] args) {
    List<User> userList = new ArrayList<>();userList.add(new User("东来佛组", 200000));userList.add(new User("如来佛组", 100000));userList.add(new User("未来佛组", 50000));userList.add(new User("斗战圣佛", 600));userList.add(new User("斗战圣佛", 1000));Stream<User> stream = userList.stream();// stream.filter(new Predicate<User>() {
    
// @Override
// public boolean test(User user) {
    
// return user.getAge() < 10000;
// }
// }).filter(new Predicate<User>() {
    
// @Override
// public boolean test(User user) {
    
// return user.getName().equals("斗战圣佛");
// }
// }).forEach(new Consumer<User>() {
    
// @Override
// public void accept(User user) {
    
// System.out.println("user = " + user);
// }
// });stream.filter(user -> user.getAge() < 10000).filter(user -> user.getName().equals("斗战圣佛")).forEach(user -> System.out.println("user = " + user));}
}

3.10、Stream排序 sorted

public class Test18 {
    public static void main(String[] args) {
    List<User> userList = new ArrayList<>();userList.add(new User("东来佛组", 200000));userList.add(new User("如来佛组", 100000));userList.add(new User("未来佛组", 50000));userList.add(new User("斗战圣佛", 600));Stream<User> stream = userList.stream();
// stream.sorted(new Comparator<User>() {
    
// @Override
// public int compare(User o1, User o2) {
    
// return o1.getAge() - o2.getAge();
// }
// }).forEach(new Consumer<User>() {
    
// @Override
// public void accept(User user) {
    
// System.out.println("user = " + user);
// }
// });stream.sorted((o1, o2) -> o1.getAge() - o2.getAge()).forEach(user -> System.out.println("user = " + user));}
}

3.11、Stream limit和skip

Limit 从头开始获取
Skip 就是跳过

public class Test19 {
    public static void main(String[] args) {
    List<User> userList = new ArrayList<>();userList.add(new User("东来佛组", 200000));userList.add(new User("如来佛组", 100000));userList.add(new User("未来佛组", 50000));userList.add(new User("斗战圣佛", 600));Stream<User> stream = userList.stream();stream.skip(2).limit(1).forEach(user -> System.out.println("user = " + user));}
}

3.12、并行流与串行流区别

串行流:

  • 单线程的方式操作; 数据量比较少的时候。

并行流:

  • 多线程方式操作;数据量比较大的时候,原理:
    Fork join 将一个大的任务拆分n多个小的子任务并行执行,
    最后在统计结果,有可能会非常消耗cpu的资源,确实可以
    提高效率。

注意:数据量比较少的情况下,不要使用并行流。

四、JDK8 Optional

  • Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
  • Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
  • Optional 类的引入很好的解决空指针异常。

4.1、判断参数是否为空

ofNullable(可以传递一个空对象)
of(不可以传递空对象,传null会报NullPointerException)

Integer a = 1;
Optional<Integer> result = Optional.ofNullable(a);
System.out.println(result.isPresent());
  • isPresent true 不为空
  • isPresent返回 false 为空。

4.2、参数为空可以设定默认值

Integer a = 1;
Optional<Integer> result = Optional.ofNullable(a);
System.out.println(result.get());
System.out.println(result.isPresent());
a = null;
Integer rs = Optional.ofNullable(a).orElse(2);
System.out.println(rs);

4.3、参数实现过滤

Integer val = 16;
Optional<Integer> result = Optional.ofNullable(val);
boolean isPresent = result.filter(a2 -> a2 > 17).isPresent();
System.out.println(isPresent);

4.4、与Lambda表达式结合使用,优化代码

4.4.1、优化方案1

// 优化前
String name = "hello";
if (name != null) {
    System.out.println(name);
}
//优化后
Optional<String> name2 = Optional.ofNullable(name);
// 当value 不为空时,则不会调用
//name2.ifPresent(s -> System.out.println(s));
name2.ifPresent(System.out::print);

4.4.2、优化方案2

public class Test26 {
    private static User user = null;public static void main(String[] args) {
    User user = Test26.getUser();System.out.println(user);}public static User getUser() {
    // 优化前
// if (user == null){
    
// return createUser();
// }
// return user;// 优化后
// return Optional.ofNullable(user).orElseGet(new Supplier<User>() {
    
// @Override
// public User get() {
    
// return createUser();
// }
// });return Optional.ofNullable(user).orElseGet(() -> createUser());}private static User createUser() {
    return new User("java", 25);}
}

4.4.3、优化方案3

map中获取的返回值自动被Optional包装,即返回值 -> Optional<返回值>

flatMap中返回值保持不变,但必须是Optional类型,即Optional<返回值> -> Optional<返回值>

public class Test27 {
    public static void main(String[] args) {
    String name = Test27.getName();System.out.println(name);}public static String getName() {
    User user = new User("Java521", 66);// 优化前写法:
// if (user != null) {
    
// String name = user.getName();
// if (name != null) {
    
// return name.toLowerCase();
// }
// }
// return null;//优化后写法:return Optional.ofNullable(user).map(user1 -> {
    return user1.getName();}).map(name -> {
    return name.toLowerCase();}).orElse(null);}
}
  相关解决方案