java8新特性之--函数式接口加方法引用与构造器引用详细讲解

简介: java8新特性之--函数式接口加方法引用与构造器引用详细讲解

函数式(Functional)接口

什么是函数式(Functional)接口

只包含一个抽象方法的接口,称为函数式接口。


你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式 抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽 象方法上进行声明)。


我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检 查它是否是一个函数式接口。同时


javadoc 也会包含一条声明,说明这个 接口是一个函数式接口。


在java.util.function包下定义了Java 8 的丰富的函数式接口

如下图所示

函数式接口举例

自定义函数式接口

注意接口名后面不要带括号

函数式接口中使用泛型:

在新特性中函数名后面可以指定泛型

作为参数传递 Lambda 表达式

为了将 Lambda 表达式作为参数传递,

接收Lambda 表达式的参数类型必须是与该 Lambda 表达式兼容的函数式接口的类型。

Java 内置四大核心函数式接口

代码示范

Predicate 断言型接口:
public class TestLambda3 {
  //Predicate<T> 断言型接口:
  @Test
  public void test4(){
    List<String> list = Arrays.asList("Hello", "atguigu", "Lambda", "www", "ok");
    List<String> strList = filterStr(list, (s) -> s.length() > 3);
    for (String str : strList) {
      System.out.println(str);
    }
  }
  //需求:将满足条件的字符串,放入集合中
  public List<String> filterStr(List<String> list, Predicate<String> pre){
    List<String> strList = new ArrayList<>();
    for (String str : list) {
      if(pre.test(str)){
        strList.add(str);
      }
    }
    return strList;
  }
}
Function<T, R> 函数型接口
public class TestLambda3 {
  //Function<T, R> 函数型接口:
  @Test
  public void test3(){
    String newStr = strHandler("\t\t\t 感谢大家观看", (str) -> str.trim());
    System.out.println(newStr);
    String subStr = strHandler("谢谢", (str) -> str.substring(2, 5));
    System.out.println(subStr);
  }
  //需求:用于处理字符串
  public String strHandler(String str, Function<String, String> fun){
    return fun.apply(str);
  }
}
Supplier 供给型接口
public class TestLambda3 {  
  //Supplier<T> 供给型接口 :
  @Test
  public void test2(){
    List<Integer> numList = getNumList(10, () -> (int)(Math.random() * 100));
    for (Integer num : numList) {
      System.out.println(num);
    }
  }
  //需求:产生指定个数的整数,并放入集合中
  public List<Integer> getNumList(int num, Supplier<Integer> sup){
    List<Integer> list = new ArrayList<>();
    for (int i = 0; i < num; i++) {
      Integer n = sup.get();
      list.add(n);
    }
    return list;
  }
Supplier 供给型接口
  //Consumer<T> 消费型接口 :
  @Test
  public void test1(){
    happy(10000, (m) -> System.out.println("大家好一瓶水:" + m + "元"));
  } 
  public void happy(double money, Consumer<Double> con){
    con.accept(money);
  }
}

其他接口

总结

何时使用lambda表达式?


当需要对一个函数式接口实例化的时候,可以使用 lambda 表达式。


何时使用给定的函数式接口?


如果我们开发中需要定义一个函数式接口,首先看看在已有的jdk提供的函数式接口是否提供了能满足需求

的函数式接口。如果有,则直接调用即可,不需要自己再自定义了。


这样极大的帮助了程序员减轻了代码的繁杂

方法引用与构造器引用


当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!


方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。


要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的 方法的参数列表和返回值类型保持一致! 格式:使用操作符 “::” 将类(或对象) 与 方法名分隔开来。


如下三种主要使用情况:

  • 对象::实例方法名
  • 类::静态方法名
  • 类::实例方法名


使用要求


要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同!(针对于1和2)


当函数式接口方法的第一个参数是需要引用方法的调用者,并且第二个参数是需要引用方法的参数(或无参数)时:ClassName::methodName(针对于3)


使用建议


如果给函数式接口提供实例,恰好满足方法引用的使用情境,就可以考虑使用方法引用给函数式接口提供实例。如果不熟悉方法引用,那么还可以使用 lambda 表达式。

方法引用代码示例

对象的引用 :: 实例方法名

//对象的引用 :: 实例方法名
  @Test
  public void test2(){
    Employee emp = new Employee(101, "张三", 18, 9999.99);
    Supplier<String> sup = () -> emp.getName();
    System.out.println(sup.get());
    System.out.println("----------------------------------");
    Supplier<String> sup2 = emp::getName;
    System.out.println(sup2.get());
  }

类名 :: 实例方法名

//类名 :: 实例方法名
  @Test
  public void test5(){
    BiPredicate<String, String> bp = (x, y) -> x.equals(y);
    System.out.println(bp.test("abcde", "abcde"));
    System.out.println("-----------------------------------------");
    BiPredicate<String, String> bp2 = String::equals;
    System.out.println(bp2.test("abc", "abc"));
    System.out.println("-----------------------------------------");
    Function<Employee, String> fun = (e) -> e.show();
    System.out.println(fun.apply(new Employee()));
    System.out.println("-----------------------------------------");
    Function<Employee, String> fun2 = Employee::show;
    System.out.println(fun2.apply(new Employee()));
  }

类名 :: 静态方法名

  //类名 :: 静态方法名
  @Test
  public void test4(){
    Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
    System.out.println("-------------------------------------");
    Comparator<Integer> com2 = Integer::compare;
  }
  @Test
  public void test3(){
    BiFunction<Double, Double, Double> fun = (x, y) -> Math.max(x, y);
    System.out.println(fun.apply(1.5, 22.2));
    System.out.println("--------------------------------------------------");
    BiFunction<Double, Double, Double> fun2 = Math::max;
    System.out.println(fun2.apply(1.2, 1.5));
  }

构造器引用

格式: ClassName::new

与函数式接口相结合,自动与函数式接口中方法兼容。 可以把构造器引用赋值给定义的方法,要求构造器参数列表要与接口中抽象 方法的参数列表一致!且方法的返回值即为构造器对应类的对象。

  @Test
  public void test7(){
    Function<String, Employee> fun = Employee::new;
    BiFunction<String, Integer, Employee> fun2 = Employee::new;
  }

数组引用

格式: type[] :: new

代码示范

//数组引用
  @Test
  public void test8(){
    Function<Integer, String[]> fun = (args) -> new String[args];
    String[] strs = fun.apply(10);
    System.out.println(strs.length);
    System.out.println("--------------------------");
    Function<Integer, Employee[]> fun2 = Employee[] :: new;
    Employee[] emps = fun2.apply(20);
    System.out.println(emps.length);
  }


目录
相关文章
|
3天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
28 6
|
21天前
|
安全 Java 开发者
Java中WAIT和NOTIFY方法必须在同步块中调用的原因
在Java多线程编程中,`wait()`和`notify()`方法是实现线程间协作的关键。这两个方法必须在同步块或同步方法中调用,这一要求背后有着深刻的原因。本文将深入探讨为什么`wait()`和`notify()`方法必须在同步块中调用,以及这一机制如何确保线程安全和避免死锁。
36 4
|
21天前
|
Java
深入探讨Java中的中断机制:INTERRUPTED和ISINTERRUPTED方法详解
在Java多线程编程中,中断机制是协调线程行为的重要手段。了解和正确使用中断机制对于编写高效、可靠的并发程序至关重要。本文将深入探讨Java中的`Thread.interrupted()`和`Thread.isInterrupted()`方法的区别及其应用场景。
24 4
|
19天前
|
Java 数据处理 数据安全/隐私保护
Java处理数据接口方法
Java处理数据接口方法
24 1
|
20天前
|
Java API
Java中内置的函数式接口
Java中内置的函数式接口
20 2
|
Java
JAVA方法的定义
JAVA方法的定义
94 0
|
6月前
|
安全 Java 编译器
杭州 【Java基础知识 11】java泛型方法的定义和使用(学习+改进+自己理解,想法) (借鉴-侵-删)
杭州 【Java基础知识 11】java泛型方法的定义和使用(学习+改进+自己理解,想法) (借鉴-侵-删)
43 1
|
7月前
|
存储 Java
Java数组与带参数方法:定义、调用及实践
Java数组与带参数方法:定义、调用及实践
79 1
|
7月前
|
存储 Java
Java中带返回值方法的定义与调用技术
Java中带返回值方法的定义与调用技术
105 1
|
7月前
|
Java
Java一分钟之-方法定义与调用基础
【5月更文挑战第8天】本文介绍了Java编程中的方法定义和调用,包括基本结构、常见问题和避免策略。方法定义涉及返回类型、参数列表和方法体,易错点有返回类型不匹配、参数错误和忘记返回值。在方法调用时,要注意参数传递、静态与非静态方法的区分,以及重载方法的调用。避免错误的策略包括明确返回类型、参数校验、理解值传递、区分静态和非静态方法以及合理利用重载。通过学习和实践,可以提升编写清晰、可维护代码的能力。
227 0