带你理解 Java 8 的函数式接口使用和自定义

2023年 8月 14日 40.5k 0

函数式接口是 Java 8 引入的一种接口,用于支持函数式编程。函数式接口通常包含一个抽象方法,可以被 Lambda 表达式或方法引用所实现。在本文中,我们将深入探讨函数式接口的概念、用途以及如何创建和使用函数式接口。

什么是函数式接口

函数式接口是只包含一个抽象方法的接口。但是默认方法和静态方法在此接口中可以定义多个。Java 中的函数式接口可以被用作 Lambda 表达式的目标类型。通过函数式接口,可以实现更简洁、更具可读性的代码,从而支持函数式编程的思想。

常见函数式接口

Java 中有一些内置的函数式接口,用于不同的用途:

  • Runnable: 用于描述可以在单独线程中执行的任务。
  • Callable: 类似于 Runnable,但可以返回执行结果或抛出异常。
  • Comparator: 用于比较两个对象的顺序。
  • Function: 接受一个参数并产生一个结果。
  • Predicate: 接受一个参数并返回一个布尔值,用于判断条件是否满足。
  • Supplier: 不接受参数,但返回一个值。
  • 自定义函数式接口

    自定义函数式接口是需要在接口上添加 @FunctionalInterface 注解

    定义 CustomFunctionalInterface 接口函数

    @java.lang.FunctionalInterface
    public interface CustomFunctionalInterface {
       void execute();
    }
    

    在上述代码中,定义了一个名为 CustomFunctionalInterface 的函数式接口,其中包含一个抽象方法 execute,这是一个无参无返回值的方法。通过使用 @FunctionalInterface 注解,明确告诉编译器这是一个函数式接口,确保它只包含一个抽象方法。

    基于 CustomFunctionalInterface 使用

    public class CustomFunctionInterfaceTest {
    
      public void test(CustomFunctionalInterface functionalInterface) {
        functionalInterface.execute();
      }
    
      @Test
      public void execute() {
        test(() -> System.out.println("Hello World Custom!"));
      }
    }
    

    在测试类 CustomFunctionInterfaceTest 中,定义了一个名为 test 的方法,接受一个 CustomFunctionalInterface 参数,并在方法体中调用了 execute 方法。这个方法允许将任意实现了 CustomFunctionalInterface 的 Lambda 表达式传递进来,并执行其 execute 方法。

    在测试方法 execute 中,通过调用 test 方法,传递了一个 Lambda 表达式 () -> System.out.println("Hello World Custom!")。这个 Lambda 表达式实现了 CustomFunctionalInterface 的抽象方法 execute,即打印了一条 "Hello World Custom!" 的消息。

    常见函数式接口基本使用

    Predicate

    当涉及到对集合或数据进行筛选时,Java 中的函数式接口 Predicate 可以发挥重要作用。Predicate 是一个通用的函数式接口,用于定义一个接受参数并返回布尔值的操作,用于判断条件是否满足。

    Predicate 函数式接口

    @FunctionalInterface
    public interface Predicate {
        boolean test(T t);
    }
    

    基于 Predicate 进行筛选

    import java.util.ArrayList;
    import java.util.List;
    import java.util.function.Predicate;
    
    public class PredicateExample {
    
        public static List filterStrings(List list, Predicate predicate) {
            List filteredList = new ArrayList();
            for (String str : list) {
                if (predicate.test(str)) {
                    filteredList.add(str);
                }
            }
            return filteredList;
        }
    
        public static void main(String[] args) {
            List stringList = List.of("apple", "banana", "cherry", "date", "elderberry");
            Predicate lengthPredicate = str -> str.length() > 5;
            List longStrings = filterStrings(stringList, lengthPredicate);
            System.out.println("Long strings: " + longStrings);
        }
    }
    

    在这个示例中,我们定义了一个 filterStrings 方法,它接受一个字符串列表和一个 Predicate 参数,并返回符合条件的字符串列表。在 main 方法中,我们创建了一个长度判断的 Predicate,然后使用它来筛选出长度大于 5 的字符串。

    Consumer

    函数式接口 Consumer 在 Java 中用于表示接受一个参数并且没有返回值的操作。它可以用于执行一些对输入数据的处理,例如打印、修改等。

    Consumer 函数式接口

    @FunctionalInterface
    public interface Consumer {
        void accept(T t);
    }
    

    基于 Consumer 进行筛选

    import java.util.ArrayList;
    import java.util.List;
    import java.util.function.Consumer;
    
    public class ConsumerExample {
    
            public static void processIntegers(List list, Consumer consumer) {
            for (Integer num : list) {
                consumer.accept(num);
            }
        }
    
        public static void main(String[] args) {
            List integerList = List.of(1, 2, 3, 4, 5);
            Consumer squareAndPrint = num -> {
                int square = num * num;
                System.out.println("Square of " + num + " is: " + square);
            };
            processIntegers(integerList, squareAndPrint);
        }
    }
    

    在这个示例中,我们定义了一个 filterStrings 方法,它接受一个字符串列表和一个 Predicate 参数,并返回符合条件的字符串列表。在 main 方法中,我们创建了一个长度判断的 Predicate,然后使用它来筛选出长度大于 5 的字符串。

    在这个示例中,我们定义了一个 processIntegers 方法,它接受一个整数列表和一个 Consumer 参数,并在方法内遍历列表,对每个元素执行 accept 方法。在 main 方法中,我们创建了一个 Consumer 实现 squareAndPrint,它会计算每个元素的平方并打印出来。

    Function

    函数式接口 Function 在 Java 中用于表示一个接受一个参数并产生一个结果的操作。它可以用于执行各种转换、映射和处理操作。

    Function 函数式接口

    Function 接口定义了一个名为 apply 的抽象方法,接受一个参数并返回一个结果。这个接口用于表示一个对输入数据的转换操作。

    @FunctionalInterface
    public interface Function {
        R apply(T t);
    }
    

    在上述定义中,T 表示输入类型,R 表示输出类型。

    基于 Function 进行数据转换

    转换为大写
    import java.util.function.Function;
    
    public class FunctionExample {
    
        public static String convertToUpperCase(String input, Function function) {
            return function.apply(input);
        }
        public static void main(String[] args) {
            String original = "hello world";
            String upperCase = convertToUpperCase(original, str -> str.toUpperCase());
            System.out.println(upperCase);
        }
    }
    

    在这个示例中,我们定义了一个 convertToUpperCase 方法,它接受一个字符串和一个 Function 参数,用于将输入字符串转换为大写。在 main 方法中,我们通过传递一个 Function 实现来执行转换操作。

    字符串长度映射
    import java.util.List;
    import java.util.function.Function;
    import java.util.stream.Collectors;
    
    public class FunctionExample {
    
        public static List mapStringLengths(List list, Function function) {
            return list.stream()
                    .map(function)
                    .collect(Collectors.toList());
        }
    
        public static void main(String[] args) {
            List strings = List.of("apple", "banana", "cherry", "date");
            List lengths = mapStringLengths(strings, str -> str.length());
            System.out.println(lengths);
        }
    }
    

    在这个示例中,我们定义了一个 mapStringLengths 方法,它接受一个字符串列表和一个 Function 参数,用于将输入字符串映射为它们的长度。通过使用 map 操作,我们在列表中的每个字符串上执行了长度映射。

    Supplier

    函数式接口 Supplier 在 Java 中用于表示一个不接受参数但产生一个结果的操作。它通常用于延迟计算,只在需要时才执行操作并生成结果。

    Supplier 函数式接口

    Supplier 接口定义了一个名为 get 的抽象方法,用于获取一个结果。这个接口用于表示一个无参操作,只产生结果。

    javaCopy code
    @FunctionalInterface
    public interface Supplier {
        T get();
    }
    

    在上述定义中,T 表示结果的类型

    基于 Supplier 进行延迟计算

    随机数生成
    import java.util.Random;
    import java.util.function.Supplier;
    
    public class SupplierExample {
    
        public static int generateRandomNumber(Supplier supplier) {
            return supplier.get();
        }
    
        public static void main(String[] args) {
            Supplier randomSupplier = () -> new Random().nextInt(100);
            int randomNumber = generateRandomNumber(randomSupplier);
            System.out.println("Random number: " + randomNumber);
        }
    }
    

    在这个示例中,我们定义了一个 generateRandomNumber 方法,它接受一个 Supplier 参数,并通过调用 get 方法获取随机数。在 main 方法中,我们创建了一个随机数生成的 Supplier,然后将它传递给 generateRandomNumber 方法来获取随机数。

    延迟初始化
    import java.util.function.Supplier;
    
    public class SupplierExample {
    
        private String expensiveResource = null;
    
        public String getExpensiveResource(Supplier supplier) {
            if (expensiveResource == null) {
                expensiveResource = supplier.get();
            }
            return expensiveResource;
        }
    
        public static void main(String[] args) {
            Supplier resourceSupplier = () -> {
                System.out.println("Initializing expensive resource...");
                return "Expensive Resource";
            };
            SupplierExample example = new SupplierExample();
            System.out.println(example.getExpensiveResource(resourceSupplier));
            System.out.println(example.getExpensiveResource(resourceSupplier));
        }
    }
    

    在这个示例中,我们定义了一个 getExpensiveResource 方法,它接受一个 Supplier 参数,并使用延迟初始化的方式获取昂贵的资源。在 main 方法中,我们创建了一个资源初始化的 Supplier,然后多次调用 getExpensiveResource 方法,观察只有在需要时才会初始化资源。

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论