盘点java8 stream中隐藏的函数式接口

简介: `shigen`是一位坚持更新文章的博客作者,记录成长历程,分享认知见解,留住感动瞬间。本文介绍了函数式接口的概念及其在Java中的应用,包括`Comparator`、`Runnable`、`Callable`等常见接口,并详细讲解了`Function`、`Predicate`、`Consumer`、`Supplier`和`Comparator`等函数式接口的使用方法及应用场景,展示了如何利用这些接口简化代码并提高编程效率。**个人IP:shigen**,与shigen一起,每天进步一点点!

shigen坚持更新文章的博客写手,记录成长,分享认知,留住感动。个人IP:shigen

提到函数式接口,最常见的就是lambda表达式,IDEA也有智能的提示:

idea智能提示

最后改成这样的就是最简洁的、IDEA希望的风格:

List<String> nameList = users.stream().map(User::getName).collect(Collectors.toList());
log.info("nameList:{}", nameList);

直接一行搞定比较复杂的功能。今天要讲到的函数式接口就从这个展开。

1. 函数式接口

所谓的函数式接口指的是只定义一个抽象方法的接口。接口类常用这个注解@FunctionalInterface表明:

  • java.util.Comparator
public interface Comparator<T> {
   
   
    int compare(T o1, T o2);
}
  • java.lang.Runnable
public interface Runnable {
   
   
    void run();
}
  • java.util.concurrent.Callable
public interface Callable<V> {
   
   
    V call() throws Exception;
}

实现起来基本上是这样的:

(o1, o2) -> o1.getXxx() > o2.getXxx()
() -> void
() -> V类型的对象

其中,callable最常见在多线程上,这里展示下我对于分布式锁的封装:

callable案例:分布式锁封装

2. 常用的函数式接口

或许对于Function、Predicate等等你并不陌生,好熟悉、好像在哪里用过就是想不起来!我们还是用stream()流来讲解。前提是构建一个用户列表:

构建数据

相信截图里User类的属性一目了然。现在我们用stream流来操作。

2.1 Function出现

List<String> nameList = users.stream().map(user -> user.getName()).collect(Collectors.toList());
log.info("nameList:{}", nameList);

这里的逻辑很简单,获得所有的用户名字返回集合。不知道有没有好奇过map,他的参数是什么:

map的参数

额,就是一个Function!好的,我这样改造下:

    static Function<User, String> nameFunction = user -> user.getName();

    public static void main(String[] args) {
   
   

        List<String> nameList = users.stream().map(nameFunction).collect(Collectors.toList());
        log.info("nameList:{}", nameList);
    }

其实Function就是两个类型约束,一个数参数类型,一个是返回值类型,定义了一个固定的逻辑。这个还好,如果稍加对于name的处理,并且是通用的处理方式,就可以考虑用Function写成一个通用的方法。

2.2 Predicate出现

Function类似,Predicate顾名思义,就是断言。可以从stream.filter()中获得:

User user1 = users.stream().filter(user -> "李四".equals(user.getName())).findFirst().orElse(null);
log.info("user1:{}", user1);

filter-predicate

对应的改造:

    static Predicate<User> namePredicate = user -> "李四".equals(user.getName());

    public static void main(String[] args) {
   
   
        User user1 = users.stream().filter(namePredicate).findFirst().orElse(null);
        log.info("user1:{}", user1);
    }

Predicate的范型只有一个,就是一个对象,返回的就是断言的方法。

2.3 Cousumer的出现

直接给出代码案例:

        Consumer<User> userConsumer = user -> {
   
   
            String name = user.getName();
            log.info("name:{}", name);
        };

        userConsumer.accept(users.get(0));

适用场景:访问类型T的对象,对其执行某些操作。只有操作,没有返回值,也不需要关注返回值。另外附上我最近看到的一段模板代码:

    /**
     * 利用设计模式减少样板代码
     */
    public static void readLine(String filename, Consumer<String> consumer) {
   
   
        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
   
   
            String line;
            while ((line = reader.readLine()) != null) {
   
   
                consumer.accept(line);
            }
        } catch (IOException e) {
   
   
            throw new RuntimeException("Error reading file", e);
        }
    }



    public static void main(String[] args) {
   
   
        String filePath = "/Users/shigen/Downloads/area.json";
        readLine(filePath, (lines) -> {
   
   
            System.out.println(lines);
        });
    }

2.4 Supplier的出现

还是先上代码:

        Supplier<User> userSupplier = () -> new User("10005", "shigen", null);
        User user2 = userSupplier.get();
        log.info("user2:{}", user2);
        userConsumer.accept(user2);

这里正好和Consumer相反,这里是生产对象的,然后可以供它消费。

适用场景:定义类型T的对象的生产规则。这里列出一个案例:生成随机数的方法:

        Supplier<Integer> randomSupplier = () -> new Random().nextInt(100);
        log.info("randomSupplier:{}", randomSupplier.get());

突然感觉曾经写过的工具类可以用这种方式简化一下了。

2.5 Comparator的出现

其实我们用的最多的还是实现Comparator的接口,重写compare方法用来比较对象,多见于需要内存排序的场景:

Comparator接口

也可以在stream.sorted()的参数中看出来:

stream.sorted()

        Comparator<User> userComparator =
            (user4, user5) -> user5.getName().compareTo(user4.getName());

        List<String> sortedName = users.stream().sorted(userComparator).map(User::getId).collect(Collectors.toList());
        log.info("sortedName:{}", sortedName);

当然,其它的高级复合Lambda表达式用法,可以参考这篇文章:系统学习lambda表达式。个人认为在业务代码使用复合lambda表达式,会加重代码的理解难度,不推荐。了解常见的函数式接口,并会使用即可。

与shigen一起,每天不一样!

目录
相关文章
|
2天前
|
数据采集 JSON Java
利用Java获取京东SKU接口指南
本文介绍如何使用Java通过京东API获取商品SKU信息。首先,需注册京东开放平台账号并创建应用以获取AppKey和AppSecret。接着,查阅API文档了解调用方法。明确商品ID后,构建请求参数并通过HTTP客户端发送请求。最后,解析返回的JSON数据提取SKU信息。注意遵守API调用频率限制及数据保护法规。此方法适用于电商平台及其他数据获取场景。
|
7天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
37 6
|
21天前
|
存储 Java 数据挖掘
Java 8 新特性之 Stream API:函数式编程风格的数据处理范式
Java 8 引入的 Stream API 提供了一种新的数据处理方式,支持函数式编程风格,能够高效、简洁地处理集合数据,实现过滤、映射、聚合等操作。
36 6
|
21天前
|
Java API 开发者
Java中的Lambda表达式与Stream API的协同作用
在本文中,我们将探讨Java 8引入的Lambda表达式和Stream API如何改变我们处理集合和数组的方式。Lambda表达式提供了一种简洁的方法来表达代码块,而Stream API则允许我们对数据流进行高级操作,如过滤、映射和归约。通过结合使用这两种技术,我们可以以声明式的方式编写更简洁、更易于理解和维护的代码。本文将介绍Lambda表达式和Stream API的基本概念,并通过示例展示它们在实际项目中的应用。
|
24天前
|
Java API
Java中内置的函数式接口
Java中内置的函数式接口
23 2
|
29天前
|
Java
在Java中如何实现接口?
实现接口是 Java 编程中的一个重要环节,它有助于提高代码的规范性、可扩展性和复用性。通过正确地实现接口,可以使代码更加灵活、易于维护和扩展。
50 3
|
28天前
|
Java
在Java中,接口之间可以继承吗?
接口继承是一种重要的机制,它允许一个接口从另一个或多个接口继承方法和常量。
77 1
|
28天前
|
Java 开发者
在 Java 中,一个类可以实现多个接口吗?
这是 Java 面向对象编程的一个重要特性,它提供了极大的灵活性和扩展性。
61 1
|
28天前
|
Java
在Java中实现接口的具体代码示例
可以根据具体的需求,创建更多的类来实现这个接口,以满足不同形状的计算需求。希望这个示例对你理解在 Java 中如何实现接口有所帮助。
42 1
|
1月前
|
Java Android开发
Eclipse 创建 Java 接口
Eclipse 创建 Java 接口
27 1
下一篇
DataWorks