JDK8新特性入门到精通

一、 接口中默认方法修饰为普通方法
1. 在jdk8之前

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

接口定义方法:public 抽象方法 需要子类实现
接口定义变量:public、static、final

2. 在JDK 1.8开始

支持使用static和default 修饰 可以写方法体,不需要子类重写。
方法:
普通方法 可以有方法体
抽象方法 没有方法体需要子类实现 重写。

3. 案例演练
public interface JDK8Interface {
    
    

    void addOrder();

    default void getDefaultOrder(){
    
    
        System.out.println("我是默认方法");
    }

    static void getStaticOrder(){
    
    
        System.out.println("我是静态方法");
    }
}


public class JDK8InterfaceImpl implements JDK8Interface {
    
    
    @Override
    public void addOrder() {
    
    
        System.out.println("addOrder");
    }
}
二、Lambda表达式
2.1. 什么是Lambda表达式

LAMBADA 好处: 简化我们匿名内部类的调用。
Lambda+方法引入 代码变得更加精简。

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

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

// 使用lambda调用有参函数
@FunctionalInterface
public interface CarryParamInterface {
    
    
    String carryParam(int i, int j);
}
    @Test
    public void lambdaCarryParamTest() {
    
    
        // 1.使用匿名内部类调用有参数函数方法
        // String result = new CarryParamInterface() {
    
    
        //     @Override
        //     public String carryParam(int i, int j) {
    
    
        //         return i + "-" + j;
        //     }
        // }.carryParam(1, 1);
        // System.out.println(result);

        //2.lambda 精简写法优化
        //如果方法体只有一条return的情况下不需要些{
    
    }return
        // CarryParamInterface carryParamInterface = (a, b) -> a + "-" + b;
        // System.out.println(carryParamInterface.carryParam(2, 6));

        //3.lambda 精简写法优化
        ((CarryParamInterface) (a, b) -> a + "-" + b).carryParam(1, 2);
        System.out.println(((CarryParamInterface) (a, b) -> a + "-" + b).carryParam(1, 2));
    }
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. 函数接口定义
//使用lambda调用无参函数
@FunctionalInterface
public interface NoParamInterface {
    
    
    void get();
}
// 使用lambda调用有参函数
@FunctionalInterface
public interface CarryParamInterface {
    
    
    String carryParam(int i, int j);
}
2.5. Lambda基础语法
()---参数列表
 -> 分隔
{
    
    }   方法体
(a,b)->{
    
    
}

无参方法调用
带参数方法调用

(函数接口的参数列表 不需要写类型 需要定义参数名称)->{
    
    方法体}

():函数方法参数列表
->分隔 {
    
    }方法体
(a,b)->{
    
    
Sout(a,b)
}

Lambda语法:
():参数列表
->分隔
{
    
    }:方法体
()->{
    
    }

无参方法调用

//使用lambda调用无参函数
@FunctionalInterface
public interface NoParamInterface {
    
    
    void get();
}

   //使用lambda调用无参函数
    @Test
    public void lambdaNoParamTest() {
    
    
        //lambda无参数调用
        //精简写法1: 如果方法体中只有一条语句的情况下 可以不需要写{
    
    }
        // NoParamInterface noParamInterface = () -> System.out.println("lambda无参数调用->精简写法1");
        // noParamInterface.get();

        //精简写法2
        ((NoParamInterface) () -> System.out.println("lambda无参数调用->精简写法2")).get();
    }
// 使用lambda调用有参函数
@FunctionalInterface
public interface CarryParamInterface {
    
    
    String carryParam(int i, int j);
}
 // 使用lambda调用有参函数
    @Test
    public void lambdaCarryParamTest() {
    
    
        // 1.使用匿名内部类调用有参数函数方法
        // String result = new CarryParamInterface() {
    
    
        //     @Override
        //     public String carryParam(int i, int j) {
    
    
        //         return i + "-" + j;
        //     }
        // }.carryParam(1, 1);
        // System.out.println(result);

        //2.lambda 精简写法优化
        //如果方法体只有一条return的情况下不需要些{
    
    }return
        // CarryParamInterface carryParamInterface = (a, b) -> a + "-" + b;
        // System.out.println(carryParamInterface.carryParam(2, 6));

        //3.lambda 精简写法优化
        ((CarryParamInterface) (a, b) -> a + "-" + b).carryParam(1, 2);
        System.out.println(((CarryParamInterface) (a, b) -> a + "-" + b).carryParam(1, 2));
    }
2.6. 方法引入

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

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

  • 静态方法引入
@FunctionalInterface
public interface MessageInterface {
    
    
    void get(Integer i);
}

public class MethodReference {
    
    
    //静态方法引入
    public static void getStaticMethod(Integer i) {
    
    
        System.out.println("我是静态方法");
    }
}
    //静态方法引入
    @Test
    public void staticMethodInto() {
    
    
        // 1.使用匿名内部类的形式 调用get方法
        // new MessageInterface() {
    
    
        //     @Override
        //     public void get(Integer i) {
    
    
        //         MethodReference.getStaticMethod(i);
        //     }
        // }.get(1);

        //2.lambda 形式
        // MessageInterface messageInterface = (i) -> {
    
    
        //     MethodReference.getStaticMethod(i);
        // };
        // messageInterface.get(2);
        //处理逻辑只有一行大括号可以省略
        // MessageInterface messageInterface = (i) -> MethodReference.getStaticMethod(i);
        // messageInterface.get(2);

        //3.使用方法引入,必须满足方法引入的方法必须和函数中的方法参数列表和返回值保持一致
        // MessageInterface messageInterface = MethodReference::getStaticMethod;
        // messageInterface.get(2);

        /**
         * 分析
         * (i) -> MethodReference.getStaticMethod(i) 等于 MethodReference::getStaticMethod
         * lambda 使用方法引入,要求:必须满足方法引入的方法必须和函数中的方法参数列表和返回值保持一致
         */

        //精简写法
        ((MessageInterface) MethodReference::getStaticMethod).get(2);
    }

-实例方法引入

@FunctionalInterface
public interface MessageInterface2 {
    
    
    String getMessage();
}

public class MethodInto {
    
    
//实例方法引入
    @Test
    public void exampleMethodInto() {
    
    
        // MethodInto methodInto = new MethodInto();
        // MessageInterface2 messageInterface2 = () -> methodInto.objGet();
        // System.out.println(messageInterface2.getMessage());

        MethodInto methodInto = new MethodInto();
        MessageInterface2 messageInterface2 = methodInto::objGet;
        System.out.println(messageInterface2.getMessage());

    }
       //实例对昂方法
    public String objGet() {
    
    
        return "1111111";
    }
}
  • 构造函数引入
@FunctionalInterface
public interface UserInterface {
    
    
    User getUser();
}

   //构造函数引入
    @Test
    public void functionMethodInto() {
    
    
        // UserInterface userInterface = () -> {
    
    
        //     return new User();
        // };

        UserInterface userInterface = User::new;
        System.out.println(userInterface.getUser());
    }
  • 对象方法引入
@FunctionalInterface
public interface LyService {
    
    
    String get(ObjMethodInto objMethodInto);
}
public class ObjMethodInto {
    
    
    //对象方法引入
    public static void main(String[] args) {
    
    
        //1.使用匿名内部类形式
        // LyService lyService = new LyService() {
    
    
        //     @Override
        //     public String get(ObjMethodInto objMethodInto) {
    
    
        //         return objMethodInto.objGet();
        //     }
        // };
        // System.out.println(lyService.get(new ObjMethodInto()));

        //2.lambda
        // LyService lyService = (objMethodInto) -> objMethodInto.objGet();
        // System.out.println(lyService.get(new ObjMethodInto()));

        //3.对象方法引入
        // LyService lyService = ObjMethodInto::objGet;
        // System.out.println(lyService.get(new ObjMethodInto()));
        /**
         * 分析
         * ObjMethodInto::objGet 等同于 (objMethodInto) -> objMethodInto.objGet()
         */
    //    案例
    //    需要将string类型的字符串获取长度

        // Function<String, Integer> stringIntegerFunction = (str)->str.length();
        // System.out.println(stringIntegerFunction.apply("gblfy"));
        Function<String, Integer> stringIntegerFunction = String::length;
        System.out.println(stringIntegerFunction.apply("gblfy"));
    }

    //实例对昂方法
    public String objGet() {
    
    
        return "1111111";
    }
}

2.7. Lambda实战案例

Foreach

    //lambda实现集合遍历
    @Test
    public void dataErgodic() {
    
    
        //案例:lambda实现集合遍历
        List<String> list = new ArrayList<>();

        list.add("gblfy.com");
        list.add("gblfy.com2");
        list.add("gblfy.com3");

        //1.普通写法
        // list.forEach(new Consumer<String>() {
    
    
        //     @Override
        //     public void accept(String s) {
    
    
        //         System.out.println(s);
        //     }
        // });

        //2.lambda精简写法
        list.forEach(p -> System.out.println(p));
    }

Lambda集合排序

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@EqualsAndHashCode
public class User {
    
    
    private String name;
    private int age;
}
  //Lambda集合排序
    @Test
    public void lambdaSort(){
    
    
        List<User> list = userList();
        list.sort((u1,u2)-> u1.getAge()-u2.getAge());
    }
    
	 //测试集合数据
    public List<User> userList() {
    
    
        List<User> list = new ArrayList<>();

        list.add(new User("yuxin", 5));
        list.add(new User("yuze", 2));
        list.add(new User("ly", 22));
        list.add(new User("zz", 15));
        list.add(new User("gb", 22));
        list.add(new User("gb", 20));
        list.add(new User("gb", 25));
        list.add(new User("gb", 26));
        list.add(new User("gb", 28));
        list.add(new User("gb", 27));
        return list;
    }
  • 线程调用
// lambda实现线程调用
    @Test
    public void lambdaThread() {
    
    
        //1.匿名内部类调用线程
        // new Thread(new Runnable() {
    
    
        //     @Override
        //     public void run() {
    
    
        //         System.out.println("匿名内部类调用线程");
        //     }
        // }).start();

        //2.lambda调用线程
        new Thread(() -> System.out.println("lambda调用线程")).start();
    }
三、java 8 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 :非常方便精简的形式遍历集合实现 过滤、排序等。

Mysql:select userName from mayikt where userName =‘mayikt’
Order by age limt(0,2)

在这里插入图片描述

3.2. Stream创建方式

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

//Stream创建方式
    @Test
    public void lambdaStream(){
    
    
        List<User> list = new ArrayList<>();

        list.add(new User("yuxin", 5));
        list.add(new User("yuze", 2));
        list.add(new User("ly", 22));
        list.add(new User("zz", 15));
        list.add(new User("gb", 22));
        list.add(new User("gb", 20));
        list.add(new User("gb", 25));
        list.add(new User("gb", 26));
        list.add(new User("gb", 28));
        list.add(new User("gb", 27));

        list.stream();
        list.parallelStream();
    }
3.3. Stream将list转换为Set
  // stream将list集合转换为set
    @Test
    public void streamListToSet() {
    
    
        List<User> list = userList();
        /**
         * 创建stream流
         * parallelStream为并行流采用多线程执行
         * Stream采用单线程执行
         * parallelStream效率比Stream要高
         */
        //将集合转化为set,然后,进行循环遍历
        list.stream().collect(Collectors.toSet()).forEach(p -> System.out.println(p));
    }
3.4. Stream将list集合转换成map
   // stream将list集合转换成map
    @Test
    public void streamListToMap() {
    
    
        List<User> list = userList();

        //list 集合只有元素 key list转换成map集成的想境况下 指定key-->User对象中的username属性 value User对象
        //new Function<User(value map), String(key map)>   map函数形式为Map<String,User>
        //lambda写法
        // list.stream().collect(Collectors.toMap(new Function<User, String>() {
    
    
        //     //这里指的是map中的key用list中的name
        //     @Override
        //     public String apply(User user) {
    
    
        //         return user.getName();
        //     }
        // }, new Function<User, User>() {
    
    
        //     //这里指的是map中的value用list中的User对象
        //     @Override
        //     public User apply(User user) {
    
    
        //         return user;
        //     }
        // })).forEach(new BiConsumer<String, User>() {
    
    
        //     //这里的forEach只是为了看效果,遍历map中的key和value,如果没有遍历请求可以不做forEach
        //     @Override
        //     public void accept(String key, User user) {
    
    
        //         System.out.println(key + "," + user);
        //     }
        // });

        //简写形式,如果不熟练建议使用idea辅助生成简写形式
        list.stream().collect(Collectors.toMap(user -> user.getName(), user -> user)).forEach((key, user) -> System.out.println(key + "," + user));
    }
3.5. Stream将Reduce 求和
    // stream计算求和
    @Test
    public void streamSum() {
    
    
        // Integer sum = Stream.of(10, 12, 8, 15, 20).reduce(new BinaryOperator<Integer>() {
    
    
        //     @Override
        //     public Integer apply(Integer integer, Integer integer2) {
    
    
        //         return integer + integer2;
        //     }
        // }).get();

        // Integer sum = Stream.of(10, 12, 8, 15, 20).reduce((i1, i2) -> i1 + i2).get();
        // System.out.println(sum);

        //    案例
        List<User> list = userList();
        // User u = list.stream().reduce(new BinaryOperator<User>() {
    
    
        //     //这里返回值User对象,因此,new User实例返回,如果是数字的话可以直接返回
        //     @Override
        //     public User apply(User user, User user2) {
    
    
        //         return new User("sum", user.getAge() + user2.getAge());
        //     }
        // }).get();
        //这里返回值User对象,因此,new User实例返回,如果是数字的话可以直接返回
        //简写
        User u = list.stream().reduce((u1, u2) -> new User("sum", u1.getAge() + u2.getAge())).get();
        System.out.println(u);
        System.out.println("age sum->" + u.getAge());
    }
3.6. Stream查找最大值和最小值
    // stream查找最大值和最小值
    @Test
    public void streamFindMaxAndMin() {
    
    
        List<User> list = userList();
        // User user = list.stream().max(new Comparator<User>() {
    
    
        //     @Override
        //     public int compare(User o1, User o2) {
    
    
        //         return o1.getAge() - o2.getAge();
        //     }
        // }).get();
        // User user = list.stream().max((u1, u2) -> u1.getAge() - u2.getAge()).get();
        // System.out.println("max age->" + user.getAge());

        User user = list.stream().min((o1, o2) -> o1.getAge() - o2.getAge()).get();
        System.out.println("min age->" + user.getAge());
    }
3.7. Stream Match用法

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

  // stream的Match用法
    @Test
    public void streamMatch() {
    
    
        List<User> list = userList();

        //    匹配任意一个就返回true
        // boolean b = list.stream().anyMatch(user -> "ly".equals(user.getName()));
        // System.out.println("test anyMatch->" + b);

        //    全部匹配就返回true
        boolean b = list.stream().allMatch(user -> "ly".equals(user.getName()));
        System.out.println("test allMatch->" + b);
    }
3.8. Stream For循环
   // stream For循环
    @Test
    public void streamFor() {
    
    
        List<User> list = userList();
        list.stream().forEach(u-> System.out.println(u));
    }
3.9. Stream filter过滤器
    // stream过滤器的用法
    @Test
    public void streamFilter() {
    
    
        List<User> list = userList();
        // list.stream().filter(user -> {
    
    
        //     //过滤username等于gb
        //     // return USER_NAME.equals(user.getName());
        //
        //     //过滤username等于gb并且年龄大于20
        //     return USER_NAME.equals(user.getName()) && user.getAge() > 20;
        // }).forEach(u -> System.out.println(u));

        //lambda简写
        list.stream().filter(user -> USER_NAME.equals(user.getName())).forEach(u -> System.out.println(u));
        list.stream().filter(user -> USER_NAME.equals(user.getName()) && user.getAge() > 20).forEach(u -> System.out.println(u));
    }
3.10. Stream排序 sorted
    //stream实现对数据排序
    @Test
    public void dataSort() {
    
    
        List<User> list = userList();

        // list.sort(new Comparator<User>() {
    
    
        //     @Override
        //     public int compare(User o1, User o2) {
    
    
        //         //默认正序排列
        //         // return o1.getAge() - o2.getAge();
        //         //倒序排列
        //         return o2.getAge() - o1.getAge();
        //
        //     }
        // });

        //正序排序从小到大
        // list.stream().sorted((u1, u2) -> u1.getAge() - u2.getAge()).forEach(user -> System.out.println(user));
        //倒序排序从大到小
        list.stream().sorted((u1, u2) -> u2.getAge() - u1.getAge()).forEach(user -> System.out.println(user));
    }
3.11. Stream limit和skip
    // stream  skip limit用法
    @Test
    public void streamLimit() {
    
    
        List<User> list = userList();
        //取集合的前2条数据
        // list.stream().limit(2).forEach(u -> System.out.println(u));

        //    跳过前2条,从第3条开始取,取2条
        // list.stream().skip(2).limit(2).forEach(u -> System.out.println(u));

        // 从头取3条数据,跳过前2条,那么只会剩余一条数据
        list.stream().limit(3).skip(2).forEach(u -> System.out.println(u));
    }
3.11. Stream综合案例
    /**
     * stream 综合案例
     * 要求
     * 1.用户信息按照年领倒序
     * 2.用户数据中包含gb
     * 3.从用户信息组去前2名
     */
    @Test
    public void streamMultipleCase() {
    
    
        List<User> list = userList();
        //1.用户信息按照年领倒序
        list.stream().sorted((u1, u2) -> u2.getAge() - u1.getAge())
                //2.用户数据中包含gb
                .filter(user -> USER_NAME.equals(user.getName()))
                //3.从用户信息组去前2名
                .limit(2)
                .forEach(user -> System.out.println(user));
    }
3.12. Stream并行流与串行流区别

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

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

四、JDK8Optional

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

4.1. 判断参数是否为空
//判断参数是否为空
    //说明:空字符串不为null
    @Test
    public void isNull() {
    
    
        /**
         * ofNullable(可以传递一个空对象)
         * Of(不可以传递空对象)
         */
        String username = "gbl";
        // String username = "";
        // String username = null;
        Optional<String> optional = Optional.ofNullable(username);
        // Optional<String> optional = Optional.of(username);
        boolean present = optional.isPresent();
        if (present) {
    
    
            System.out.println("username不为空");
        }
    }
4.2. 参数为空可以设定默认值
   //参数为空可以设定默认值
    @Test
    public void isNullSetDefault() {
    
    
        // String username = null;
        String username = "gbl";
        String optional = Optional.ofNullable(username).orElse("123456");
        System.out.println(optional);
    }
4.3. 参数实现过滤
    //参数实现过滤
    @Test
    public void paramFilter() {
    
    
        String username = null;
        boolean present = Optional.ofNullable(username).filter(p -> USER_NAME.equals(p)).isPresent();
        System.out.println(present);
    }
五、lambda 搭配使用

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

5.1. 优化方案1
//与Lambda表达式结合使用,优化代码
    @Test
    public void ifPresent() {
    
    
        String username = null;
        //优化前
        if (username != null) {
    
    
            System.out.println(username);
        }

        //优化后
        //lambda 简写形式
        // Optional.ofNullable(username).ifPresent(s -> System.out.println(s));
        //方法引入 简写形式
        Optional.ofNullable(username).ifPresent(System.out::print);
    }
5.2. 优化方案2
import java.util.Optional;
import java.util.function.Supplier;

public class Test01 {
    
    
    private static User user = null;

    public static void main(String[] args) {
    
    
        User user = Test01.getUser();
        System.out.println(user);

    }

    public static User getUser() {
    
    
        // 优化前
        // if (user == null) {
    
    
        //     return createUser();
        // }
        // return user;

        //第1种:这种处理方案适用于只有一步操作,在此案例中会出现user全局对象为null的场景
        // return Optional.ofNullable(user).orElse(createUser());

        //第2种:这种方案适用于符合逻辑之前做预处理的一些操作,可解决第一种全局user对象为空
        // return Optional.ofNullable(user).orElseGet(() -> {
    
    
        //     user = createUser();
        //     return user;
        // });

        //第3种:方法引入
        return Optional.ofNullable(user).orElseGet(Test01::createUser);
    }

    private static User createUser() {
    
    
        return new User("123456", 2);
    }
}

5.3. 优化方案3

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

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

package com.gblfy.elk.lambda;

import com.gblfy.elk.entity.User;

import java.util.Optional;

public class Test02 {
    
    
    public static void main(String[] args) {
    
    
        String orderName = Test02.getOrderName();
        System.out.println(orderName);
    }

    public static String getOrderName() {
    
    
        // 优化前写法:
        User user = new User("GBLFY.COM", 10);
        //1.先判断user对象是否为null
        // if (user != null) {
    
    
        //2.user对象不为null,则获取username
        //     String userName = user.getName()
        //3.username不为null,转小写
        //     if (userName != null) {
    
    
        //         return userName.toLowerCase();
        //     }
        // }
        // Optional<User> userOptional1 = Optional.ofNullable(user);
        // Optional<String> optional = userOptional1.map(u -> u.getName());
        // Optional<String> toLowerCase = optional.map(name -> name.toLowerCase());
        // return toLowerCase.get();


        return
                //1.先判断user对象是否为null
                Optional.ofNullable(user)
                //2.user对象不为null,则获取username
                .map(u -> u.getName())
                //3.username不为null,转小写,为null返回null
                .map(un -> un.toLowerCase()).orElse(null);
    }
}
六、归纳梳理
6.1. 经验分享

1.lambda使用必须为函数接口,需要@FunctionalInterface注解修饰,并且只能有一个抽象方法。(object父类先不计数)
2.lambda只是对内部类的的写法简写代码,使用咱们操作内部类方便许多
3.lambda stream 提高了咱们对数据的效率(循环遍历、判断、list与set与map之间的转换、排序、分页->取数据前几条、跳过指定条数的数据等等),但是,使用时要对中间操作和终止操作,要分清,一旦用了终止操作就无法在使用中间操作。
4.方法引入4种,这个需要认真理解,4种方法引入的区别和使用场景,勤加练习,熟能生巧。
5.普通代码转换lambda不熟练时,前期可以先利用idea辅助,使用stream进行操作数据或者重构代码时,建议先把普通代码的逻辑实现的流程写下来,然后再按照流程,一步一步优化重构,刚开始不要求快,按照此思路勤加练习,养成这样的习惯,慢慢的就会提升你重构代码的能力,我就是这样做的,好了,分享就到这吧!小伙伴们,我们一起加油!

6.2. 练习案例汇总

User对象

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@EqualsAndHashCode
public class User {
    
    
    private String name;
    private int age;
}

无参接口

//使用lambda调用无参函数
@FunctionalInterface
public interface NoParamInterface {
    
    
    void get();
}

有参接口

// 使用lambda调用有参函数
@FunctionalInterface
public interface CarryParamInterface {
    
    
    String carryParam(int i, int j);
}

lambda案例

package com.gblfy.lambda;

import com.gblfy.elk.entity.User;
import com.gblfy.elk.lambda.CarryParamInterface;
import com.gblfy.elk.lambda.NoParamInterface;
import org.junit.Test;

import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.OptionalLong;
import java.util.stream.Collectors;
import java.util.stream.LongStream;

public class LambdaCase {
    
    

    public static final String USER_NAME = "gb";

    //使用lambda调用无参函数
    @Test
    public void lambdaNoParamTest() {
    
    
        //lambda无参数调用
        //精简写法1: 如果方法体中只有一条语句的情况下 可以不需要写{
    
    }
        // NoParamInterface noParamInterface = () -> System.out.println("lambda无参数调用->精简写法1");
        // noParamInterface.get();

        //精简写法2
        ((NoParamInterface) () -> System.out.println("lambda无参数调用->精简写法2")).get();
    }

    // 使用lambda调用有参函数
    @Test
    public void lambdaCarryParamTest() {
    
    
        // 1.使用匿名内部类调用有参数函数方法
        // String result = new CarryParamInterface() {
    
    
        //     @Override
        //     public String carryParam(int i, int j) {
    
    
        //         return i + "-" + j;
        //     }
        // }.carryParam(1, 1);
        // System.out.println(result);

        //2.lambda 精简写法优化
        //如果方法体只有一条return的情况下不需要些{
    
    }return
        // CarryParamInterface carryParamInterface = (a, b) -> a + "-" + b;
        // System.out.println(carryParamInterface.carryParam(2, 6));

        //3.lambda 精简写法优化
        ((CarryParamInterface) (a, b) -> a + "-" + b).carryParam(1, 2);
        System.out.println(((CarryParamInterface) (a, b) -> a + "-" + b).carryParam(1, 2));
    }

    //测试集合数据
    public List<User> userList() {
    
    
        List<User> list = new ArrayList<>();

        list.add(new User("yuxin", 5));
        list.add(new User("yuze", 2));
        list.add(new User("ly", 22));
        list.add(new User("zz", 15));
        list.add(new User("gb", 22));
        list.add(new User("gb", 20));
        list.add(new User("gb", 25));
        list.add(new User("gb", 26));
        list.add(new User("gb", 28));
        list.add(new User("gb", 27));
        return list;
    }

    //lambda实现集合遍历
    @Test
    public void dataErgodic() {
    
    
        //案例:lambda实现集合遍历
        List<String> list = new ArrayList<>();

        list.add("gblfy.com");
        list.add("gblfy.com2");
        list.add("gblfy.com3");

        //1.普通写法
        // list.forEach(new Consumer<String>() {
    
    
        //     @Override
        //     public void accept(String s) {
    
    
        //         System.out.println(s);
        //     }
        // });

        //2.lambda精简写法
        list.forEach(p -> System.out.println(p));
    }

    //Lambda集合排序
    @Test
    public void lambdaSort(){
    
    
        List<User> list = userList();
        list.sort((u1,u2)-> u1.getAge()-u2.getAge());
    }
    // lambda实现线程调用
    @Test
    public void lambdaThread() {
    
    
        //1.匿名内部类调用线程
        // new Thread(new Runnable() {
    
    
        //     @Override
        //     public void run() {
    
    
        //         System.out.println("匿名内部类调用线程");
        //     }
        // }).start();

        //2.lambda调用线程
        new Thread(() -> System.out.println("lambda调用线程")).start();
    }

    //Stream创建方式
    @Test
    public void lambdaStream(){
    
    
        List<User> list = new ArrayList<>();

        list.add(new User("yuxin", 5));
        list.add(new User("yuze", 2));
        list.add(new User("ly", 22));
        list.add(new User("zz", 15));
        list.add(new User("gb", 22));
        list.add(new User("gb", 20));
        list.add(new User("gb", 25));
        list.add(new User("gb", 26));
        list.add(new User("gb", 28));
        list.add(new User("gb", 27));

        list.stream();
        list.parallelStream();
    }
    // stream将list集合转换为set
    @Test
    public void streamListToSet() {
    
    
        List<User> list = userList();
        /**
         * 创建stream流
         * parallelStream为并行流采用多线程执行
         * Stream采用单线程执行
         * parallelStream效率比Stream要高
         */
        //将集合转化为set,然后,进行循环遍历
        list.stream().collect(Collectors.toSet()).forEach(p -> System.out.println(p));
    }

    // stream将list集合转换成map
    @Test
    public void streamListToMap() {
    
    
        List<User> list = userList();

        //list 集合只有元素 key list转换成map集成的想境况下 指定key-->User对象中的username属性 value User对象
        //new Function<User(value map), String(key map)>   map函数形式为Map<String,User>
        //lambda写法
        // list.stream().collect(Collectors.toMap(new Function<User, String>() {
    
    
        //     //这里指的是map中的key用list中的name
        //     @Override
        //     public String apply(User user) {
    
    
        //         return user.getName();
        //     }
        // }, new Function<User, User>() {
    
    
        //     //这里指的是map中的value用list中的User对象
        //     @Override
        //     public User apply(User user) {
    
    
        //         return user;
        //     }
        // })).forEach(new BiConsumer<String, User>() {
    
    
        //     //这里的forEach只是为了看效果,遍历map中的key和value,如果没有遍历请求可以不做forEach
        //     @Override
        //     public void accept(String key, User user) {
    
    
        //         System.out.println(key + "," + user);
        //     }
        // });

        //简写形式,如果不熟练建议使用idea辅助生成简写形式
        list.stream().collect(Collectors.toMap(user -> user.getName(), user -> user)).forEach((key, user) -> System.out.println(key + "," + user));
    }

    // stream计算求和
    @Test
    public void streamSum() {
    
    
        // Integer sum = Stream.of(10, 12, 8, 15, 20).reduce(new BinaryOperator<Integer>() {
    
    
        //     @Override
        //     public Integer apply(Integer integer, Integer integer2) {
    
    
        //         return integer + integer2;
        //     }
        // }).get();

        // Integer sum = Stream.of(10, 12, 8, 15, 20).reduce((i1, i2) -> i1 + i2).get();
        // System.out.println(sum);

        //    案例
        List<User> list = userList();
        // User u = list.stream().reduce(new BinaryOperator<User>() {
    
    
        //     //这里返回值User对象,因此,new User实例返回,如果是数字的话可以直接返回
        //     @Override
        //     public User apply(User user, User user2) {
    
    
        //         return new User("sum", user.getAge() + user2.getAge());
        //     }
        // }).get();
        //这里返回值User对象,因此,new User实例返回,如果是数字的话可以直接返回
        //简写
        User u = list.stream().reduce((u1, u2) -> new User("sum", u1.getAge() + u2.getAge())).get();
        System.out.println(u);
        System.out.println("age sum->" + u.getAge());
    }

    // stream查找最大值和最小值
    @Test
    public void streamFindMaxAndMin() {
    
    
        List<User> list = userList();
        // User user = list.stream().max(new Comparator<User>() {
    
    
        //     @Override
        //     public int compare(User o1, User o2) {
    
    
        //         return o1.getAge() - o2.getAge();
        //     }
        // }).get();
        // User user = list.stream().max((u1, u2) -> u1.getAge() - u2.getAge()).get();
        // System.out.println("max age->" + user.getAge());

        User user = list.stream().min((o1, o2) -> o1.getAge() - o2.getAge()).get();
        System.out.println("min age->" + user.getAge());
    }

    // stream的Match用法
    @Test
    public void streamMatch() {
    
    
        List<User> list = userList();

        //    匹配任意一个就返回true
        // boolean b = list.stream().anyMatch(user -> "ly".equals(user.getName()));
        // System.out.println("test anyMatch->" + b);

        //    全部匹配就返回true
        boolean b = list.stream().allMatch(user -> "ly".equals(user.getName()));
        System.out.println("test allMatch->" + b);
    }
    // stream For循环
    @Test
    public void streamFor() {
    
    
        List<User> list = userList();
        list.stream().forEach(u-> System.out.println(u));
    }

    // stream过滤器的用法
    @Test
    public void streamFilter() {
    
    
        List<User> list = userList();
        // list.stream().filter(user -> {
    
    
        //     //过滤username等于gb
        //     // return USER_NAME.equals(user.getName());
        //
        //     //过滤username等于gb并且年龄大于20
        //     return USER_NAME.equals(user.getName()) && user.getAge() > 20;
        // }).forEach(u -> System.out.println(u));

        //lambda简写
        list.stream().filter(user -> USER_NAME.equals(user.getName())).forEach(u -> System.out.println(u));
        list.stream().filter(user -> USER_NAME.equals(user.getName()) && user.getAge() > 20).forEach(u -> System.out.println(u));
    }

    // stream  skip limit用法
    @Test
    public void streamLimit() {
    
    
        List<User> list = userList();
        //取集合的前2条数据
        // list.stream().limit(2).forEach(u -> System.out.println(u));

        //    跳过前2条,从第3条开始取,取2条
        // list.stream().skip(2).limit(2).forEach(u -> System.out.println(u));

        // 从头取3条数据,跳过前2条,那么只会剩余一条数据
        list.stream().limit(3).skip(2).forEach(u -> System.out.println(u));
    }

    //stream实现对数据排序
    @Test
    public void dataSort() {
    
    
        List<User> list = userList();

        // list.sort(new Comparator<User>() {
    
    
        //     @Override
        //     public int compare(User o1, User o2) {
    
    
        //         //默认正序排列
        //         // return o1.getAge() - o2.getAge();
        //         //倒序排列
        //         return o2.getAge() - o1.getAge();
        //
        //     }
        // });

        //正序排序从小到大
        // list.stream().sorted((u1, u2) -> u1.getAge() - u2.getAge()).forEach(user -> System.out.println(user));
        //倒序排序从大到小
        list.stream().sorted((u1, u2) -> u2.getAge() - u1.getAge()).forEach(user -> System.out.println(user));
    }

    /**
     * stream 综合案例
     * 要求
     * 1.用户信息按照年领倒序
     * 2.用户数据中包含gb
     * 3.从用户信息组去前2名
     */
    @Test
    public void streamMultipleCase() {
    
    
        List<User> list = userList();
        //1.用户信息按照年领倒序
        list.stream().sorted((u1, u2) -> u2.getAge() - u1.getAge())
                //2.用户数据中包含gb
                .filter(user -> USER_NAME.equals(user.getName()))
                //3.从用户信息组去前2名
                .limit(2)
                .forEach(user -> System.out.println(user));
    }


    //    并行流底层实现原理
    @Test
    public void streamSingleThread() {
    
    

        Instant start = Instant.now();
        long sum = 0;
        for (int i = 0; i < 500000000L; i++) {
    
    
            sum += i;
        }
        System.out.println(sum);
        Instant end = Instant.now();
        //单线程 602毫秒
        System.out.println("5亿数据求和花费的时间->" + Duration.between(start, end).toMillis() + "毫秒");
    }

    //    并行流底层实现原理
    @Test
    public void streamParallel() {
    
    
        Instant start = Instant.now();
        LongStream longStream = LongStream.rangeClosed(0, 500000000L);
        OptionalLong result = longStream.parallel().reduce((left, right) -> left + right);
        System.out.println(result.getAsLong());
        Instant end = Instant.now();
        //多线程 613毫秒
        System.out.println("5亿数据求和花费的时间->" + Duration.between(start, end).toMillis() + "毫秒");
    }
}

方法引入

package com.gblfy.lambda;

import com.gblfy.elk.entity.User;
import com.gblfy.elk.lambda.drawinto.*;
import org.junit.Test;

public class MethodInto {
    
    

    //静态方法引入
    @Test
    public void staticMethodInto() {
    
    
        // 1.使用匿名内部类的形式 调用get方法
        // new MessageInterface() {
    
    
        //     @Override
        //     public void get(Integer i) {
    
    
        //         MethodReference.getStaticMethod(i);
        //     }
        // }.get(1);

        //2.lambda 形式
        // MessageInterface messageInterface = (i) -> {
    
    
        //     MethodReference.getStaticMethod(i);
        // };
        // messageInterface.get(2);
        //处理逻辑只有一行大括号可以省略
        // MessageInterface messageInterface = (i) -> MethodReference.getStaticMethod(i);
        // messageInterface.get(2);

        //3.使用方法引入,必须满足方法引入的方法必须和函数中的方法参数列表和返回值保持一致
        // MessageInterface messageInterface = MethodReference::getStaticMethod;
        // messageInterface.get(2);

        /**
         * 分析
         * (i) -> MethodReference.getStaticMethod(i) 等于 MethodReference::getStaticMethod
         * lambda 使用方法引入,要求:必须满足方法引入的方法必须和函数中的方法参数列表和返回值保持一致
         */

        //精简写法
        ((MessageInterface) MethodReference::getStaticMethod).get(2);
    }

    //实例方法引入
    @Test
    public void exampleMethodInto() {
        // MethodInto methodInto = new MethodInto();
        // MessageInterface2 messageInterface2 = () -> methodInto.objGet();
        // System.out.println(messageInterface2.getMessage());

        MethodInto methodInto = new MethodInto();
        MessageInterface2 messageInterface2 = methodInto::objGet;
        System.out.println(messageInterface2.getMessage());

    }

    //实例对昂方法
    public String objGet() {
    
    
        return "1111111";
    }


    //构造函数引入
    @Test
    public void functionMethodInto() {
    
    
        // UserInterface userInterface = () -> {
    
    
        //     return new User();
        // };

        UserInterface userInterface = User::new;
        System.out.println(userInterface.getUser());
    }


}

对象方法引入

@FunctionalInterface
public interface LyService {
    
    
    String get(ObjMethodInto objMethodInto);
}

pac
kage com.gblfy.elk.lambda.drawinto;

import java.util.function.Function;

public class ObjMethodInto {
    
    
    //对象方法引入
    public static void main(String[] args) {
    
    
        //1.使用匿名内部类形式
        // LyService lyService = new LyService() {
    
    
        //     @Override
        //     public String get(ObjMethodInto objMethodInto) {
    
    
        //         return objMethodInto.objGet();
        //     }
        // };
        // System.out.println(lyService.get(new ObjMethodInto()));

        //2.lambda
        // LyService lyService = (objMethodInto) -> objMethodInto.objGet();
        // System.out.println(lyService.get(new ObjMethodInto()));

        //3.对象方法引入
        // LyService lyService = ObjMethodInto::objGet;
        // System.out.println(lyService.get(new ObjMethodInto()));
        /**
         * 分析
         * ObjMethodInto::objGet 等同于 (objMethodInto) -> objMethodInto.objGet()
         */
    //    案例
    //    需要将string类型的字符串获取长度

        // Function<String, Integer> stringIntegerFunction = (str)->str.length();
        // System.out.println(stringIntegerFunction.apply("gblfy"));
        Function<String, Integer> stringIntegerFunction = String::length;
        System.out.println(stringIntegerFunction.apply("gblfy"));
    }

    //实例对昂方法
    public String objGet() {
    
    
        return "1111111";
    }
}

OptionalCase

package com.gblfy.lambda;

import org.junit.Test;

import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Predicate;

public class OptionalCase {
    
    
    public static final String USER_NAME = "gb";

    //判断参数是否为空
    //说明:空字符串不为null
    @Test
    public void isNull() {
    
    
        /**
         * ofNullable(可以传递一个空对象)
         * Of(不可以传递空对象)
         */
        String username = "gbl";
        // String username = "";
        // String username = null;
        Optional<String> optional = Optional.ofNullable(username);
        // Optional<String> optional = Optional.of(username);
        boolean present = optional.isPresent();
        if (present) {
    
    
            System.out.println("username不为空");
        }
    }

    //参数为空可以设定默认值
    @Test
    public void isNullSetDefault() {
    
    
        // String username = null;
        String username = "gbl";
        String optional = Optional.ofNullable(username).orElse("123456");
        System.out.println(optional);
    }

    //参数实现过滤
    @Test
    public void paramFilter() {
    
    
        String username = null;
        boolean present = Optional.ofNullable(username).filter(p -> USER_NAME.equals(p)).isPresent();
        System.out.println(present);
    }

    //与Lambda表达式结合使用,优化代码
    @Test
    public void ifPresent() {
    
    
        String username = null;
        //优化前
        if (username != null) {
    
    
            System.out.println(username);
        }

        //优化后
        //lambda 简写形式
        // Optional.ofNullable(username).ifPresent(s -> System.out.println(s));
        //方法引入 简写形式
        Optional.ofNullable(username).ifPresent(System.out::print);
    }

    //    优化方案2
    @Test
    public void ifPresent2() {
    
    

    }
}

猜你喜欢

转载自blog.csdn.net/weixin_40816738/article/details/123454009