Java的函数式接口编程示例
创始人
2025-07-13 09:31:16
0

背景

函数式接口是在Java 8中引入的,与Lambda表达式和方法引用一起。这三个特性被添加到Java中,以促进函数式编程并编写干净、可读的代码。在Java 8之前,需要编写大量样板代码来涵盖基本功能。例如,为了调用一个函数,首先我们必须创建一个具有所需方法的类,创建类的实例,然后使用实例来调用方法,或者使用具有相应方法的匿名类的另一种方式。

使用Lambda表达式,我们可以避免使用具体类和匿名类对象的需求。函数式接口更进一步,因为Lambda表达式只需要实现一个方法,所以可以轻松地实现函数式接口。

函数式接口只展示一个功能。例如,一个具有单一方法compareTo()的Comparable接口用于比较目的。但它可以有任意数量的默认方法和静态方法。

Java 8定义了许多函数式接口,可以广泛用于Lambda表达式。以下是在java.util.Function包中定义的函数式接口列表。

@FunctionalInterface注解,按照功能,任何具有单个抽象方法的接口都是函数式接口。Java提供了@FunctionalInterface注解,以将一个接口标记为函数式接口,以便编译器可以检查接口是否是函数式接口。此注解是可选的,主要是为了增加编译器的检查和增加代码的可读性和维护性。

函数式接口编程示例

函数式接口的类型:在Java中,主要有四种类型的函数式接口。

Predicate函数式接口:Predicate函数式接口是一种方法接受一个参数,并返回true或false的接口。Predicate函数式接口主要用于比较元素以进行排序或根据应用于传入的输入的某些条件来过滤值。Java提供了用于基本类型的Predicate函数式接口,如IntPredicate、DoublePredicate和LongPredicate,分别只接受Integer、Double和Long类型的参数。

用法:

Predicate predicate = (value) -> value != 0; //或者
Predicate predicate = (value) -> test(value);

在上面的代码片段中,predicate函数根据传入的值返回true或false。

示例:

在这个例子中,我们使用predicate函数式接口和lambda表达式来从一个整数列表中过滤出奇数。

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class Tester {
   public static void main(String args[]) {
      List numbers = Arrays.asList(1,2,3,4,5,6,7,8);

      Predicate isEvenNumber = n -> n %2 == 0;
      numbers =  numbers.stream().filter(isEvenNumber).toList();

      System.out.println(numbers);
   }
}

编译运行上述程序后,输出结果为:

[2, 4, 6, 8]

Consumer函数式接口:Consumer函数式接口是一种方法接受一个参数,并且不返回任何值的接口。Consumer函数式接口主要用于执行副作用操作。例如,打印一个元素、添加称谓等。还有其他变种的Consumer,比如BiConsumer。BiConsumer函数式接口可以接受两个参数。Java提供了用于基本类型的Consumer函数式接口,如IntConsumer、DoubleConsumer和LongConsumer,分别只接受Integer、Double和Long类型的参数。

用法:

//定义
Consumer consumer = (value) -> System.out.println(value);
// 或者
Consumer consumer1 = System.out::println;
// 使用
Consumer consumer2 = (value) -> accept(value);

示例:

在这个例子中,我们借助lambda表达式和方法引用,使用consumer函数式接口来打印整数列表中的所有数字。

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class Tester {
   public static void main(String args[]) {
      List numbers = Arrays.asList(1,2,3,4,5,6,7,8);

      Consumer consumer = (value) -> System.out.println(value);
      Consumer consumer1 = System.out::println;

      System.out.println("Printing using consumer functional interface as lambda expression");
      numbers.forEach(consumer);

      System.out.println("Printing using consumer functional interface as method reference");
      numbers.forEach(consumer1);
   }
}

编译运行程序结果如下:

Printing using consumer functional interface as lambda expression
1
2
3
4
5
6
7
8
Printing using consumer functional interface as method reference
1
2
3
4
5
6
7
8

Supplier函数式接口:Supplier函数式接口是一种没有任何参数传递且会返回一个值的接口。Supplier函数式接口主要用于延迟生成值。例如,获取一个随机数,生成一系列数字等。

用法:

//定义
Supplier supplier = () -> Math.random() * 10;
// 使用
Supplier supplier1 = () -> get();

示例:

在这个例子中,我们借助lambda表达式,使用Supplier函数式接口来获取一个随机数。

import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

public class Tester {
   public static void main(String args[]) {
      Supplier supplier = () -> (int)(Math.random() * 10);

      List randomNumbers = new ArrayList<>();

      // generate 10 random numbers
      for(int i = 0; i< 10; i++) {
         randomNumbers.add(supplier.get());
      }
      System.out.println(randomNumbers);
   }
}

编译并运行程序,得出运行结果:

[0, 8, 8, 8, 8, 5, 7, 5, 5, 9]

Function函数式接口:Function函数式接口是一种方法接受一个参数并返回一个值的接口。Function函数式接口主要用于获取处理后的值。例如,获取一个元素的平方,修剪字符串值等。还有其他的Function变体,比如BiFunction。BiFunction函数式接口可以接受两个参数。Java还提供了针对基本类型的Function函数式接口,如IntFunction、DoubleFunction和LongFunction,分别只接受Integer、Double和Long类型的参数。还有两个更实用的接口,UnaryOperator扩展了Function接口,BinaryOperator扩展了BiFunction接口。

用法:

//定义
Function function = (value) -> Math.random() * 10;
// 使用
Function function1 = (value) -> apply(value);

示例:

在这个例子中,我们借助lambda表达式,使用Function函数式接口来获取一个平方数。

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

public class Tester {
   public static void main(String args[]) {
      List numbers = Arrays.asList(1,2,3,4,5,6,7,8);

      Function squared = (value) -> value * value;  

      List squaredNumbers =  numbers.stream().map(squared).toList();

      System.out.println(squaredNumbers);
   }
}

编译并运行程序,得出运行结果:

[1, 4, 9, 16, 25, 36, 49, 64]

注意事项:

在Java 8之前,已经存在的许多接口被注释为函数式接口,并可以在lambda表达式中使用。例如:

  • Runnable −提供run() 方法
  • Callable − 提供 call() 方法
  • Actionlistener − 提供actionPerformed() 方法
  • Comparable − 提供 compareTo() 方法比较两个数的大小

示例:

在这个例子中,我们创建了两个线程。第一个线程使用匿名类创建,第二个线程使用lambda表达式创建。两者都使用runnable接口来创建线程实例。

public class Tester {
   public static void main(String args[]) {
      // create anonymous inner class object
      new Thread(new Runnable() {
         @Override public void run() {
            System.out.println("Thread 1 is running");
         }
      }).start();

      // lambda expression to create the object
      new Thread(() -> {
         System.out.println("Thread 2 is running.");
      }).start();   
   }
}

编译并运行程序,结果:

Thread 1 is running
Thread 2 is running.

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
着眼MAC地址,解救无法享受D... 在安装了DHCP服务器的局域网环境中,每一台工作站在上网之前,都要先从DHCP服务器那里享受到地址动...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...