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);// 增加了一种形参类型
- Consumer
- 供给型接口
- Supplier
- void get();
- Supplier
- 函数型接口
- 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
- Function<T,R>
- 断言型接口
- Predicate
- boolean test(T t)
- Predicate
- 消费型接口
-
示例
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(); }