【Java 基础篇】Java Supplier 接口详解

news2025/1/12 15:49:23

在这里插入图片描述

在Java中,Supplier接口是一个重要的函数式接口,它属于java.util.function包,用于表示一个供应商,它不接受任何参数,但可以提供一个结果。Supplier通常用于延迟计算或生成值的场景。本文将详细介绍Supplier接口的用法以及如何在实际编程中应用它。

了解 Supplier 接口

在Java中,Supplier接口的定义如下:

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

Supplier接口是一个泛型接口,其中的get()方法不接受任何参数,但返回一个泛型类型T的值。这个接口被注解为@FunctionalInterface,表明它是一个函数式接口,可以用于Lambda表达式。

Supplier接口的主要作用是延迟计算或生成值。它通常用于以下场景:

  • 惰性计算:只有在需要时才计算或获取值,而不是立即执行。
  • 生成值:用于生成一些值,例如随机数、默认配置等。

使用 Supplier 接口

基本用法

让我们从一个基本的示例开始,使用Supplier接口生成一个随机数。首先,导入必要的包:

import java.util.Random;
import java.util.function.Supplier;

然后,创建一个Supplier接口的实例,通过Lambda表达式实现get()方法来生成随机数:

Supplier<Integer> randomSupplier = () -> {
    Random random = new Random();
    return random.nextInt(100); // 生成0到99的随机数
};

int randomNumber = randomSupplier.get();
System.out.println("随机数:" + randomNumber);

在上面的示例中,我们创建了一个randomSupplier,它可以生成一个0到99之间的随机数。通过调用randomSupplier.get()方法,我们获取了随机数的值。

方法引用

Supplier接口通常与方法引用一起使用,使代码更加简洁。继续上面的示例,我们可以使用方法引用来生成随机数:

Supplier<Integer> randomSupplier = () -> new Random().nextInt(100);

int randomNumber = randomSupplier.get();
System.out.println("随机数:" + randomNumber);

上面的示例中,我们将new Random().nextInt(100)作为Supplier接口的实现,并且不再需要显式地编写return语句。

惰性计算

Supplier接口的一个强大之处在于它支持惰性计算。这意味着生成值的计算只会在需要时才执行。考虑以下示例,其中我们使用Supplier来延迟计算字符串的长度:

String text = "Hello, World!";
Supplier<Integer> lengthSupplier = () -> text.length();

// 假设有一些其他耗时操作

int length = lengthSupplier.get();
System.out.println("字符串长度:" + length);

在上面的示例中,我们创建了一个lengthSupplier,它在需要时才计算字符串的长度。如果有其他耗时操作在lengthSupplier之后,那么字符串长度的计算将被延迟到真正需要的时候。

使用 Supplier 处理异常

Supplier接口也可以用于处理异常。例如,考虑一个需要读取文件内容的情况,我们可以使用Supplier来处理可能的IOException异常:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.function.Supplier;

public class FileContentReader {
    public static void main(String[] args) {
        Supplier<String> fileContentSupplier = () -> {
            try {
                return new String(Files.readAllBytes(Paths.get("sample.txt")));
            } catch (IOException e) {
                throw new RuntimeException("文件读取失败", e);
            }
        };

        try {
            String content = fileContentSupplier.get();
            System.out.println("文件内容:" + content);
        } catch (RuntimeException e) {
            System.err.println("发生异常:" + e.getMessage());
        }
    }
}

在上面的示例中,我们创建了一个fileContentSupplier,它会尝试读取文件的内容。如果文件读取失败,它会抛出一个RuntimeException异常,其中包含了原始的IOException异常信息。

更多用法

Supplier接口的主要目的是提供一个可以供其他代码获取值的函数式接口。它的应用场景非常广泛,可以用于各种需要延迟获取或生成值的情况。以下是Supplier接口的一些更多用法:

  1. 缓存值: 可以使用Supplier来缓存某个值,以避免多次计算。例如:
Supplier<String> cachedValue = Memoizer.memoize(() -> expensiveDatabaseCall());

上述代码中,Memoizer.memoize方法用于缓存昂贵的数据库调用结果,以便在后续调用时可以直接获取缓存的值,而不必再次执行昂贵的操作。

  1. 生成随机值: Supplier可以用于生成随机值。例如,生成随机整数:
Supplier<Integer> randomIntSupplier = () -> new Random().nextInt(100);
  1. 提供默认值: 可以使用Supplier来提供默认值,如果某个值不存在,则返回默认值:
Supplier<String> valueSupplier = () -> getValueFromCacheOrDatabase();
String result = Optional.ofNullable(valueSupplier.get()).orElse("Default");

上述代码中,Optional用于处理可能为null的值,如果valueSupplier的结果为null,则返回默认值"Default"。

  1. 链式操作: 可以将多个Supplier组合成链式操作,依次获取值或执行操作:
Supplier<Integer> firstSupplier = () -> 1;
Supplier<Integer> secondSupplier = () -> 2;

Supplier<Integer> combinedSupplier = () -> {
    int firstValue = firstSupplier.get();
    int secondValue = secondSupplier.get();
    return firstValue + secondValue;
};

int result = combinedSupplier.get(); // 结果为3
  1. 懒加载: Supplier常用于实现懒加载模式,只有在需要值的时候才进行计算或初始化:
Supplier<ExpensiveObject> lazyObject = LazyInitializer.initialize(() -> createExpensiveObject());

上述代码中,LazyInitializer.initialize方法用于懒加载ExpensiveObject,只有在首次访问lazyObject.get()时才会创建ExpensiveObject

  1. 条件获取值: 可以使用Supplier来根据条件获取值。例如,根据用户角色获取相应的配置信息:
Supplier<Config> configSupplier = () -> {
    if (isAdmin()) {
        return getAdminConfig();
    } else {
        return getUserConfig();
    }
};

Config userConfig = configSupplier.get();

这些示例展示了Supplier接口的一些更多用法,它在各种情况下都能提供灵活的值获取和生成方式。通过合理利用Supplier,你可以改进代码的性能、可维护性和可读性。

注意事项

在使用Supplier接口时,有一些注意事项需要考虑:

  1. 延迟计算: Supplier通常用于延迟计算或获取值,它并不保证值的立即计算。因此,在调用get方法之前,不会执行Supplier内部的逻辑。这对于性能优化和避免不必要的计算是有益的。

  2. 可能的空值: Supplierget方法可以返回null,因此在使用时需要注意处理可能的空值情况,以避免NullPointerException

  3. 线程安全性: 如果多个线程同时访问同一个Supplier实例,并且该实例的get方法可能会修改共享状态,那么你需要确保线程安全性。你可以考虑使用synchronized关键字或其他线程同步机制来保护共享状态。

  4. 性能考虑: 如果Supplier的计算或获取操作涉及昂贵的计算或IO操作,那么你可能需要考虑性能问题。在某些情况下,你可以使用缓存或懒加载等技术来优化性能。

  5. 避免副作用: Supplier的主要目的是提供值,而不是执行副作用。虽然可以在Supplier内部执行副作用,但最好避免这样做,以保持代码的可预测性和可维护性。

  6. 错误处理: 如果Supplier内部的逻辑可能会引发异常,你需要考虑如何处理这些异常。可以使用try-catch块捕获异常并进行适当的处理。

  7. 不可变性: 如果可能的话,尽量将Supplier返回的值设计成不可变的,以避免意外的修改。如果返回的对象是可变的,那么需要特别小心,以确保不会导致意外的状态更改。

  8. 维护清晰的代码: 当使用多个Supplier组合时,要确保代码易于阅读和理解。可以使用注释或合理的命名来提高代码的可读性。

总之,Supplier是一个强大的函数式接口,可以用于各种情况下的值获取和生成。在使用时要考虑上述注意事项,以确保代码的可靠性和性能。

总结

Supplier接口是Java中用于表示供应商的函数式接口,它通常用于延迟计算或生成值的场景。本文介绍了Supplier接口的基本用法,包括创建Supplier实例、使用方法引用、惰性计算和处理异常。使用Supplier接口可以使代码更加灵活和易于维护,特别是在需要生成值或进行惰性计算的情况下。

希望本文能够帮助你更好地理解和应用Supplier接口,从而提高Java编程的效率和质量。如果你对Java函数式编程还有更多疑问,可以进一步深入学习,掌握更多高级特性和用法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1035210.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

矩阵的c++实现

在大学数学课程《线性代数》中&#xff0c;就有矩阵和行列式的出现&#xff0c;这篇文章主要讲矩阵在c中的实现和一些用途&#xff08;目前我知道的&#xff09; 此篇文章只写c的内容&#xff0c;不具体写到数学中矩阵的一些公式、性质。 本篇文章中一部分图片来自百度百科。…

Android 12,调用系统库libft2.so 遇到的各种问题记录

问题前提,Android 12系统,vendor静态库中调用 libft2.so。(vendor静态库中调用libft2.so会简单点,没这么麻烦) 【问题1】 (native:vendor) can not link against libft2 (native:platform) 本地debug尝试修改: 为了本地环境debug调试方便,我找了个 mk文件,在里面添加了…

《富足》—没有完善的个人,但是可以有完善的团队

摘要&#xff1a;在吴军老师《富足》一书上&#xff0c;阅读到一句话&#xff1a;“没有完善的个人&#xff0c;但是可以有完善的团队”。很认同这句&#xff0c;目前听见最多的可能是“没有完美的个人&#xff0c;只有完美的团队”&#xff0c;这句长挂在嘴边的话在社会工作多…

Win7开启触摸键盘方法

在Win7系统中&#xff0c;自带有触摸屏幕键盘&#xff0c;能够在屏幕上显示虚拟键盘&#xff0c;让用户可以用指针设备或触屏等进行输入操作&#xff0c;那么Win7系统怎么开启触摸键盘呢&#xff1f;想知道的小伙伴可以跟着我一起来学习一下。 1、首先打开Win7系统的开始菜单&a…

计算机竞赛 深度学习YOLO抽烟行为检测 - python opencv

文章目录 1 前言1 课题背景2 实现效果3 Yolov5算法3.1 简介3.2 相关技术 4 数据集处理及实验5 部分核心代码6 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习YOLO抽烟行为检测 该项目较为新颖&#xff0c;适合作为竞赛课…

方案:TSINGSEE青犀智能分析AI皮带撕裂算法的场景应用

在工地矿山等现实场景中&#xff0c;皮带运输在生产过程中是必不可少的&#xff0c;然而&#xff0c;由于长时间高强度的运转&#xff0c;皮带很容易发生撕裂、破损、跑偏等问题。这些问题会严重影响生产速度&#xff0c;甚至会导致严重的安全事故。为了有效预防此类安全事故发…

windows server 2019 、2012等服务器查看系统和应用程序日志

查看windows系统日志 点击左下角的windows按钮&#xff0c;输入事件两个字&#xff0c;会显示时间查看器 点击事件查看器&#xff0c;windows日志下面可以卡到系统日志和应用程序的日志 筛选时间范围内的日志 修改记录时间 选组自定义范围 选择事件事件 输入事件范围&#xff…

功能安全Part1-名词定义

半年多没搞FuSa&#xff0c;好多名词已经忘了啥意思&#xff0c;总结一下。 Part1总共为FuSa定义了184个名词。这里捡下重要的描述下。 3.3 ASIL decomposition ASIL分解&#xff1a;将安全要求冗余地分配给充分独立的要素 &#xff08;这里指系统组件[软件或者硬件]&#xff…

思源笔记-S3协议多电脑同步教程

获取数据仓库密钥 ​ ​ 首次使用可能需要先创建,然后这个密钥用于你的其他电脑的思源笔记导入这个密钥才能多个电脑使用一个同步服务(S3协议) 如下图所示,你的另一台电脑就需要导入密钥​ ​ ​ 获取S3协议的服务 如图打开思源笔记的设置 ​ ​ 然后进入云端​​ ​…

Windows安装Mysql--免安装版

在Windows系统上安装免安装版MySql的步骤 官方下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/ 将下载好的文件“mysql-5.7.18-winx64”解压缩到C盘的 目录下&#xff1a; 配置环境变量&#xff1a; &#xff08;略&#xff09; 正式安装&#xff0c;添加my.i…

Linux下的网络编程——C/S模型 UDP(三)

前言&#xff1a; UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09;是一种在计算机网络中常用的传输层协议。与TCP&#xff08;传输控制协议&#xff09;相比&#xff0c;UDP是一种无连接的协议&#xff0c;不具备可靠性和流量控制等特性&#x…

Win11蓝牙无法连接怎么办?可以试试这个方法。

蓝牙对我们电脑来说还是较为重要的一项功能&#xff0c;如果蓝牙无法连接&#xff0c;会导致很多依靠蓝牙的设备&#xff0c;如蓝牙鼠标&#xff0c;蓝牙耳机等配合电脑使用的设备无法使用&#xff0c;给我们带来不少困扰&#xff0c;遇到这种情况的时候&#xff0c;可以试试下…

c语言 static

1、静态局部变量在程序加载时初始化&#xff0c;静态局部变量的初始值写入到了data段&#xff1a; 如下代码test_symbol.c int f() {static int x 0;return x; }int g() {static int x 9;return x; }使用命令gcc -c test_symbol.c -o test_symbol 编译 使用命令 readelf -a …

LaTex打出上大下小的公式

想要在latex中打出如下word公式 首先使用 \atop符号 使用如下语句 d_{H(A,B)} max\{{sup\, inf \atop {a \in A\,b \in B}}\,d(a,b), {sup\, inf\,\atop {b\in B\,a\in\,A}}d(b,a)\}. ![在这里插入图片描述](https://img-blog.csdnimg.cn/0c842594716a4693b1124523d53bfcad…

k8s 集群 -4 pod生命周期

首先 容器环境初始化,pod 由pod 镜像来提供 在pod 生命周期里 容器主要 分文两种&#xff1a;初始化容器和主容器 初始化 容器一定要成功运行并退出&#xff0c;当初始化容器运行退出完了之后 主容器开始和运行 主容器开始运行的时候 有两个探针 存活探针和就绪探针 Pod 可…

Docker实战技巧(二):Kubernetes基础操作实战

Kubernetes定位在Saas层,重点解决了微服务大规模部署时的服务编排问题 1、关闭防火墙并设置开机禁用   systemctl stop firewalld   systemctl disable firewalld 2、配置repo   cd /etc/yum.repos.d/   下载Docker repo   wget https://mirrors.aliyun.com/docker-…

【论文写作】Latex 所有符号汇总参考

【论文写作】Latex 所有符号汇总参考 文章目录 【论文写作】Latex 所有符号汇总参考1. 希腊字母2. 数学构造3. 分割4. 累加累成等5. 标准函数名称6. 二进制符号&#xff08;关系符号&#xff09;7. 箭头8. 杂项符号&#xff08;其他的符号&#xff09;9. 数学模式重音、音节10.…

结构体-寻找爱好相同的人

任务描述 每个人有三项爱好&#xff0c;分别是食物&#xff0c;饮料&#xff0c;电影&#xff0c;运动等中的任意三项&#xff0c;第 i 个人的三种爱好分别用一个整数 ai​&#xff0c;bi​&#xff0c;ci​ 来表示。现在给出 n 个人的爱好&#xff0c;如果两个人起码有两项以…

YOLOv3模型原理深度解析

概况 &#xff08;1&#xff09;YOLOv3是YOLO系列第一次引入残差连接来解决深度网络中的梯度消失问题&#xff08;是不是第一次&#xff0c;有待你后面考证&#xff09;&#xff0c;实际用的backbone是DarkNet53 &#xff08;2&#xff09;最显著的改进&#xff0c;也是对你涨…

[Linux]线程概念

[Linux]线程概念 文章目录 [Linux]线程概念什么是线程Linux系统下的线程实现线程是CPU调度的基本单位进程是系统分配资源的基本实体二级页表 线程的优点线程的缺点线程异常线程用途线程资源 什么是线程 线程是进程内部的一个执行分支&#xff0c;执行粒度比进程更细&#xff0…