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

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

在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 {
    
    
    @Override
    public void addOrder() {
    
    
        System.out.println("添加订单");
    }
}

Test01

public static void main(String[] args) {
    
    
        //1.使用new的实现类的形式调用接口
        OrderService orderService = new OrderServiceImpl();
        orderService.addOrder();

        //2.使用匿名内部接口调用
        new OrderService() {
    
    
            @Override
            public 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() {
    
    
            @Override
            public 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() {
    
    
            @Override
            public 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() {
    
    
            @Override
            public String get(Test08 test08) {
    
    
                return test08.objGet();
            }
        };
        System.out.println(objectMethodService.get(new Test08()));

        // 2.lambda
        ObjectMethodService 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() {
    
    
            @Override
            public void get(Integer a) {
    
    
                test09.get(a);
            }
        };
        messageInterface.get(6);

        //lambda
        MessageInterface2 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() {
    
    
            @Override
            public User getUser() {
    
    
                return new User();
            }
        };
        System.out.println(userInterface.getUser());

        //lambda
        UserInterface 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>() {
    
    
            @Override
            public 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>() {
    
    
            @Override
            public 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() {
    
    
            @Override
            public 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>() {
    
    
            @Override
            public String apply(User user) {
    
    
                return user.getName();
            }
        }, new Function<User, User>() {
    
    
            @Override
            public User apply(User user) {
    
    
                return user;
            }

        }));
        collect.forEach(new BiConsumer<String, User>() {
    
    
            @Override
            public 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);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_37242720/article/details/118345484