盘点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一起,每天不一样!

目录
相关文章
|
8天前
|
算法 Java 数据处理
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。HashSet基于哈希表实现,提供高效的元素操作;TreeSet则通过红黑树实现元素的自然排序,适合需要有序访问的场景。本文通过示例代码详细介绍了两者的特性和应用场景。
29 6
|
8天前
|
存储 Java 数据处理
Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位
【10月更文挑战第16天】Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位。本文通过快速去重和高效查找两个案例,展示了Set如何简化数据处理流程,提升代码效率。使用HashSet可轻松实现数据去重,而contains方法则提供了快速查找的功能,彰显了Set在处理大量数据时的优势。
18 2
|
21小时前
|
安全 Java
在 Java 中使用实现 Runnable 接口的方式创建线程
【10月更文挑战第22天】通过以上内容的介绍,相信你已经对在 Java 中如何使用实现 Runnable 接口的方式创建线程有了更深入的了解。在实际应用中,需要根据具体的需求和场景,合理选择线程创建方式,并注意线程安全、同步、通信等相关问题,以确保程序的正确性和稳定性。
|
2天前
|
Java API 开发者
Java 8新特性之Stream API详解
【10月更文挑战第22天】Java 8引入了重要的Stream API,用于处理集合数据。本文分三部分介绍:基本概念与原理、使用方法及应用实例。Stream API支持延迟执行、惰性求值,提供过滤、映射、排序、聚合等操作,使代码更简洁、易读。文中详细讲解了创建Stream、中间操作、终端操作以及具体应用场景,如排序、过滤、映射和聚合。
8 3
|
4天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
10 3
|
4天前
|
Java
在Java多线程编程中,实现Runnable接口通常优于继承Thread类
【10月更文挑战第20天】在Java多线程编程中,实现Runnable接口通常优于继承Thread类。原因包括:1) Java只支持单继承,实现接口不受此限制;2) Runnable接口便于代码复用和线程池管理;3) 分离任务与线程,提高灵活性。因此,实现Runnable接口是更佳选择。
12 2
|
4天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
11 2
|
4天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
15 1
|
5天前
|
Java 数据处理
|
5天前
|
存储 Java 开发者
Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效
【10月更文挑战第19天】在软件开发中,随着项目复杂度的增加,数据结构的组织和管理变得至关重要。Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,帮助开发者告别混乱,提升代码质量。
14 1