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);
  }


目录
相关文章
|
2天前
|
JSON Java Apache
非常实用的Http应用框架,杜绝Java Http 接口对接繁琐编程
UniHttp 是一个声明式的 HTTP 接口对接框架,帮助开发者快速对接第三方 HTTP 接口。通过 @HttpApi 注解定义接口,使用 @GetHttpInterface 和 @PostHttpInterface 等注解配置请求方法和参数。支持自定义代理逻辑、全局请求参数、错误处理和连接池配置,提高代码的内聚性和可读性。
|
4天前
|
分布式计算 Java API
Java 8引入了流处理和函数式编程两大新特性
Java 8引入了流处理和函数式编程两大新特性。流处理提供了一种声明式的数据处理方式,使代码更简洁易读;函数式编程通过Lambda表达式和函数式接口,简化了代码书写,提高了灵活性。此外,Java 8还引入了Optional类、新的日期时间API等,进一步增强了编程能力。这些新特性使开发者能够编写更高效、更清晰的代码。
14 4
|
3天前
|
Java
java线程接口
Thread的构造方法创建对象的时候传入了Runnable接口的对象 ,Runnable接口对象重写run方法相当于指定线程任务,创建线程的时候绑定了该线程对象要干的任务。 Runnable的对象称之为:线程任务对象 不是线程对象 必须要交给Thread线程对象。 通过Thread的构造方法, 就可以把任务对象Runnable,绑定到Thread对象中, 将来执行start方法,就会自动执行Runable实现类对象中的run里面的内容。
12 1
|
6天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
36 4
|
8天前
|
Java 开发者
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
34 4
|
10天前
|
Java 测试技术 Maven
Java一分钟之-PowerMock:静态方法与私有方法测试
通过本文的详细介绍,您可以使用PowerMock轻松地测试Java代码中的静态方法和私有方法。PowerMock通过扩展Mockito,提供了强大的功能,帮助开发者在复杂的测试场景中保持高效和准确的单元测试。希望本文对您的Java单元测试有所帮助。
13 2
|
12天前
|
Java Spring
JAVA获取重定向地址URL的两种方法
【10月更文挑战第17天】本文介绍了两种在Java中获取HTTP响应头中的Location字段的方法:一种是使用HttpURLConnection,另一种是使用Spring的RestTemplate。通过设置连接超时和禁用自动重定向,确保请求按预期执行。此外,还提供了一个自定义的`NoRedirectSimpleClientHttpRequestFactory`类,用于禁用RestTemplate的自动重定向功能。
JAVA802_函数式接口的概述、Supplier供给型接口、consumer消费型接口、Predicate断定型接口、Function函数型接口(下)
③. consumer 只有输入,没有返回值 ④. Predicate有一个输入参数,返回boolean ⑤. Function:有一个输入参数,有一个输出
145 0
JAVA802_函数式接口的概述、Supplier供给型接口、consumer消费型接口、Predicate断定型接口、Function函数型接口(下)
|
4天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。