欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JDK8新特性二:方法引入详述

程序员文章站 2022-06-04 23:06:28
...

JDK8新特性

5 方法引入

5.1 定义

  • 方法引入可以结合Lambda表达式让编写的代码变得更加精简,它提供了很多非常有用的语法,可以直接引用已有java类或对象的方法或者构造器,离不开Lambda表达式。
  • 类别
    • 静态方法引入
    • 对象方法引入
    • 实例方法引入
    • 构造函数引入

5.2 方法引入规则

  • 遵守:

    • 引入的方法的形参(个数,对应位置类型)必须和函数接口中方法的形参(个数、对应位置类型)一致
    • 如果函数接口中方法没有返回值,那么引入的方法可以有返回值或者没有返回值。
    • 如果函数接口中方法有返回值,那么引入方法的返回值类型也必须保持一致
  • 不同类别方法引入的规则

    类型 方法引入的语法 Lambda表达式
    静态方法引入 Class::static_method (args)->类名.static_method(args)
    对象方法引入 Class::method (instance)->instance.method()
    实例方法引入 Instance::method (args)->对象实例.method(args)
    构造函数引入 Class::new (args)->new 类名(args)

5.3 静态方法引入

  • 接口

    @FunctionalInterface
    public interface StaticInterface {
    
        void test(int a,int b);
    }
    
  • 测试

    package com.fc.day2.service;
    
    import org.junit.Test;
    
    /**
     * @PackageName: com.fc.day2.service
     * @ClassName: StaticInterfaceTest
     * @Description: 静态方法引入
     * @Author: Fclever
     * @Date 2021/7/25 14:21
     **/
    public class StaticInterfaceTest {
    
        @Test
        public void test() {
            // Lambda表达式
            StaticInterface staticInterface1 = (a,b) -> StaticInterfaceTest.testStatic(a,b);
            staticInterface1.test(1,2);
            // 静态方法引入
            StaticInterface staticInterface2 = StaticInterfaceTest::testStatic;
            staticInterface2.test(1,2);
            // 精简写法
            ((StaticInterface)StaticInterfaceTest::testStatic).test(1,2);
        }
    
        public static void testStatic(int a, int b) {
            System.out.println(a+b);
        }
    
    }
    
    在上面例子中
    (a, b) -> StaticInterfaceTest.testStatic(a, b)
    和
    StaticInterfaceTest::testStatic
    是等价的
    静态方法中也有两个参数,会自动匹配函数接口中对应方法中的形参,这种简写的形式也只适用于函数接口方法体只有一行的情况
    
  • 说明

    • 使用静态方法引入的方式将现有的静态方法作为函数方法的方法体
    • 引入的方法的形参(个数,对应位置类型)必须和函数接口中方法的形参(个数、对应位置类型)一致
    • 如果函数接口中方法没有返回值,那么引入的方法可以有返回值
    • 如果函数接口中方法有返回值,那么引入方法的返回值类型也必须保持一致

5.4 对象方法引入

  • 实体

    package com.fc.day2.service;
    
    /**
     * @PackageName: com.fc.day2.service
     * @ClassName: TestEntiry
     * @Description:    测试实体类
     * @Author: Fclever
     * @Date 2021/7/25 23:13
     **/
    public class TestEntity {
    
        private String id;
        private String name;
    
        public TestEntity() {
        }
    
        public TestEntity(String id, String name) {
            this.id = id;
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "TestEntity{" +
                    "id='" + id + '\'' +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    
    
  • 接口

    package com.fc.day2.service;
    
    /**
     * @ClassName ObjectInterface
     * @Description 对象方法引入
     * @Author Fclever
     * @Date 2021/7/27 09:18
     **/
    public interface ObjectInterface {
    
        String get(TestEntity testEntity);
    }
    
    
  • 测试

    package com.fc.day2.service;
    
    import org.junit.Test;
    
    import static org.junit.Assert.*;
    
    /**
     * @ClassName ObjectInterfaceTest
     * @Description
     * @Author Fclever
     * @Date 2021/7/27 09:20
     **/
    public class ObjectInterfaceTest {
    
        @Test
        public void test() {
            // 创建对象实例
            TestEntity testEntity = new TestEntity("1","Tom");
            // Lambda表达式形式
            ObjectInterface objectInterface1 = (test) -> test.toString();
            System.out.println(objectInterface1.get(testEntity));
            // 对象方法引入
            ObjectInterface objectInterface2 = TestEntity::toString;
            System.out.println(objectInterface2.get(testEntity));
            // 精简写法
            System.out.println(((ObjectInterface)TestEntity::toString).get(testEntity));
        }
    }
    
  • 说明

    (test) -> test.toString()TestEntiry::toString()
    是等价的
    
    • 函数接口中方法的形参是TestEntity类型,返回值是一个TestEntity的实例对象调用的方法,就可以采用实例方法引入的方式类精简代码
    • 此时,如果函数接口中的get方法的形参值变成了其他类型的参数,那么上述的对象引入方式的代码就需要根据类型调整了

5.5 实例方法引入

  • 接口

    package com.fc.day2.service;
    
    /**
     * @PackageName: com.fc.day2.service
     * @ClassName: ObjectInterface
     * @Description:    实例方法引入
     * @Author: Fclever
     * @Date 2021/7/25 19:22
     **/
    @FunctionalInterface
    public interface InstanceInterface {
    
        void add(int a,int b);
    }
    
    
  • 测试

    package com.fc.day2.service;
    
    import org.junit.Test;
    
    import static org.junit.Assert.*;
    
    /**
     * @PackageName: com.fc.day2.service
     * @ClassName: ObjectInterfaceTest
     * @Description:    实例方法引入
     * @Author: Fclever
     * @Date 2021/7/25 19:23
     **/
    public class InstanceInterfaceTest {
    
        @Test
        public void test() {
            // 创建对象实例
            InstanceInterfaceTest instance = new InstanceInterfaceTest();
            // Lambda表达式形式
            InstanceInterface objectInterface1 = (a,b) -> instance.go(a,b);
            objectInterface1.add(1,2);
            // 对象方法引入
            InstanceInterface objectInterface2 = instance::go;
            objectInterface2.add(1,2);
            // 精简写法
            ((InstanceInterface)instance::go).add(1,2);
        }
    
        public void go(int a,int b) {
            System.out.println(a+b);
        }
    }
    
  • 说明

    • 此时(a,b) -> instance.go(a,b)和instance::go就是等价的。
    • 实例方法引入时,需要依赖于已有类的实例对象,通过指定语法调用方法即可
    • 需要遵守的规则与上面一致

5.6 构造函数引入

  • 实体类

    package com.fc.day2.service;
    
    /**
     * @PackageName: com.fc.day2.service
     * @ClassName: TestEntiry
     * @Description:    测试实体类
     * @Author: Fclever
     * @Date 2021/7/25 23:13
     **/
    public class TestEntiry {
    
        private String id;
        private String name;
    
        public TestEntiry() {
        }
    
        public TestEntiry(String id, String name) {
            this.id = id;
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "TestEntiry{" +
                    "id='" + id + '\'' +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    
    
  • 接口

    package com.fc.day2.service;
    
    /**
     * @PackageName: com.fc.day2.service
     * @ClassName: ConstructorInterface
     * @Description:    构造函数引入
     * @Author: Fclever
     * @Date 2021/7/25 20:09
     **/
    public interface ConstructorInterface {
    
        TestEntiry getEntity();
    }
    
    
  • 测试

    package com.fc.day2.service;
    
    import org.junit.Test;
    
    import static org.junit.Assert.*;
    
    /**
     * @PackageName: com.fc.day2.service
     * @ClassName: ConstructorInterfaceTest
     * @Description:
     * @Author: Fclever
     * @Date 2021/7/25 23:13
     **/
    public class ConstructorInterfaceTest {
    
        @Test
        public void test(){
            // Lambda表达式  方法体只有一行,return可以省略
            ConstructorInterface constructorInterface1 = () -> new TestEntiry();
            // 构造函数引入
            ConstructorInterface constructorInterface2 = TestEntiry::new;
            System.out.println(constructorInterface2.getEntity());
        }
    
    }
    
  • 说明

    • 上面的示例中会默认调用无参构造方法

    • 如果想要调用带参构造方法可以修改函数接口方法,然后在调用该函数接口中方法时,传递参数即可

      public interface ConstructorInterface {
      
          TestEntiry getEntity(String id,String name);
      }
      
      // 测试
      @Test
      public void test(){
          // Lambda表达式  方法体只有一行,return可以省略
          ConstructorInterface constructorInterface1 = (a,b) -> new TestEntiry();
          // 构造函数引入
          ConstructorInterface constructorInterface2 = TestEntiry::new;
          System.out.println(constructorInterface2.getEntity("1","jack"));
      }
      
    • 这样使用会自动引入对应带参的构造函数

6 Java内置的函数接口

  • 分类

    • 消费型接口
      • Consumer
        • void accept(T t);
      • BiConsumer<T,U>
        • void accept(T t,U u);// 增加了一种形参类型
    • 供给型接口
      • Supplier
        • void get();
    • 函数型接口
      • 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);// 两个相同类型形参与同类型返回值
      • ToIntFunction// 限定返回int
      • ToLongFunction// 限定返回long
      • ToDoubleFunction// 限定返回Double
      • IntFunction// 限定返回int,返回泛型R
      • LongFunction// 限定返回long,返回泛型R
      • DoubleFunction// 限定返回double,返回泛型R
    • 断言型接口
      • Predicate
        • boolean test(T t)
  • 示例

    public static void main(String[] args) {
            // Lambda表达式
            Function<String, Integer> function = (str) -> {
                return str.length();
            };
            System.out.println(function.apply("sdfjskdfj"));
            // 对象方法引入
            Function<String,Integer> function1 = String::length;
            System.out.println(function.apply("sdkfjsl"));
        }
    

7 Lambda实战示例

7.1 foreach

  • 用来遍历集合中的数据,foreach接收一个消费型函数接口Consumer,首先可以利用匿名内部类的形式去操作;同时,Consumer接口中的accept函数方法接收一个String形参,并打印输出字符串,可以使用Lambda表达式来处理,当方法体只有一行代码时,还可以省略大括号;方法使用使用System.out.println来输出,因为System.out的返回值是一个类对象,相当于在方法体内调用了该类对象的方法,可以通过实例方法引入的方式进一步简化代码。

  • 代码

    public static void main(String[] args) {
            ArrayList<String> strings = new ArrayList<>();
            strings.add("1");
            strings.add("2");
            strings.add("3");
            // 匿名内部类
            strings.forEach(new Consumer<String>() {
                @Override
                public void accept(String s) {
                    System.out.println(s);
                }
            });
            // Lambda表达式
            strings.forEach((item) -> {
                System.out.println(item);
            });
            // 对象方法引入  System.out是一个PrintStream对象,调用了println方法
            strings.forEach(System.out::println);
        }
    

7.2 集合排序

  • 使用sort方法,接收一个Comparator类型的形参

  • 代码

    public static void main(String[] args) {
            List<User> list = new ArrayList<>();
            list.add(new User("Tom1",22));
            list.add(new User("Tom2",33));
            list.add(new User("Tom3",12));
            list.add(new User("Tom4",5));
            // 匿名内部类
            list.sort(new Comparator<User>() {
                @Override
                public int compare(User o1, User o2) {
                    return o1.getAge() - o2.getAge();
                }
            });
            // Lambda表达式
            list.sort((o1,o2) -> {
                return o1.getAge() - o2.getAge();
            });
            list.sort((o1,o2) -> o1.getAge() - o2.getAge());
            // 对象方法引入
            list.sort(Comparator.comparingInt(User::getAge));
        }
    

7.3 线程调用

  • 1

  • 代码

    public static void main(String[] args) {
            // 匿名内部类
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
            thread.start();
            // Lambda表达式
            Thread thread1 = new Thread(() -> System.out.println(Thread.currentThread().getName()));
            thread1.start();
        }
    
相关标签: JDK1.8新特性