Java可选参数

在Java类中设计方法时,某些参数对于其执行而言可能是可选的。 无论是在DTO,胖模型域对象还是简单的无状态服务类中,可选方法参数都是常见的。

从本文中, 您将学习如何在Java中处理可选参数 。 我们将专注于常规方法,带有可选字段的类构造函数,并快速查看所讨论主题的不良做法。 我们将停下来看一下Java 8 Optional,并评估它是否符合我们的需求。

让我们开始吧。

1.可选方法参数

您可以通过几种不同的方法来处理Java可选参数。 我将引导您从最简单到更复杂。

@Nullable注解

为什么只是不传递null? 这是一个简单的解决方案,不需要任何额外的工作。 您没有任何需要作为方法参数之一的对象吗? 没问题。 只需传递null即可,编译器很高兴。

这里的问题是可读性。 调用方法的程序员如何知道他是否可以安全地传递null? 对于哪些参数可以接受空值,哪些是必需的?

为了清楚表明null是有效输入,可以使用@Nullable批注。

User createUser(String name, @Nullable Email email) {// ...
}

您不同意此方法声明是不言自明的吗?

可选参数

尽管很简单,但是null传递方法的问题在于它很容易失控。 团队可能会Swift开始过度使用它,并使代码库难以维护,并带有大量的空检查条件

不过,还有其他选择。

可选清单

代替null,我们有时可以创建一个空的类表示形式。 考虑一下Java集合。 如果方法接受列表或映射,则永远不要使用null作为输入。

空集合总是比空集合好,因为在大多数情况下,不需要任何特殊处理。

您可能想知道为什么要浪费内存来创建空集合。 毕竟,null不会花费您任何费用。

您的怀疑是有道理的。 幸运的是,有一个简单的解决方案。

每当需要空的代表时,就不应创建集合的新实例。 在代码库中重复使用同一实例。

你知道吗? Java已经具有您可以使用的所有集合的空实例。 您可以在Collections实用程序类中找到它们 。

User createUser(String name, List<Rights> rights) {// ...
}
import java.util.Collections;
// ...
create("bob", Collections.emptyList());

空对象模式

空集合的概念也适用于其他类。 空集合只是具有零元素的常规集合。 同样,您可以考虑应用程序中的其他对象。

Null对象是表示缺失值的类的特殊实例。 如果某些方法期望将对象作为参数,则始终可以传递Null对象表示形式,而不必担心它将在运行时导致意外的异常。

可选参数

您可以通过两种方式实现Null对象模式。

对于简单值对象,将预定义值分配给属性的默认实例就足够了。 通常,您将此Null对象公开为常量,以便可以多次重用。 例如:

public class User {public static final User EMPTY = new User("", Collections.emptyList());private final String name;private final List<Rights> rights;public User(String name, List<Rights> rights) {Objects.requireNonNull(name);Objects.requireNonNull(rights);this.name = name;this.rights = rights;}// ...}

如果您的Null对象还需要模仿通过方法公开的某些行为,则简单实例可能无法工作。 在这种情况下,您应该扩展类并覆盖此类方法。

这是扩展前一个示例的示例:

public class AnonymousUser extends User {public static final AnonymousUser INSTANCE = new AnonymousUser();private AnonymousUser() {super("", Collections.emptyList());}@Overridepublic void changeName(String newName) {throw new AuthenticationException("Only authenticated user can change the name");}}

专用的Null对象类使您可以将多个角落案例放在一个地方,这使维护更加轻松。

方法重载

如果您设计的方法带有可选参数,则可以公开该方法的重载版本。 每种方法应仅接受必需的参数。

使用这种方法,您不必期望调用方将为可选参数提供默认值。 您可以通过自己的内部重载方法传递默认值。 换句话说,您对方法的调用者隐藏了可选参数的默认值。

User createUser(String name) {this.createUser(name, Email.EMPTY);
}User createUser(String name, Email email) {Objects.requireNonNull(name);Objects.requireNonNull(rights);// ...
}

重载的方法可以相互调用,但这不是强制性的。 如果更方便,则可以独立实现每种方法。 但是,通常您会验证所有参数,并将逻辑放在参数列表最长的方法中。

值得一提的是,方法重载已在标准Java库中广泛使用。 当您学习如何设计API时,请向经验丰富的人学习。

参数对象模式

大多数开发人员都同意,当方法参数列表过长时,将变得难以阅读。 通常,您可以使用Parameter Object pattern处理问题。 参数对象是一个命名的容器类,它对所有方法参数进行分组。

是否解决了可选方法参数的问题?

不,不是。

它将问题仅移至参数对象的构造函数。

让我们看看如何用…解决这个更普遍的问题。

2.可选的构造函数参数

从带有可选参数的问题的角度来看,简单的构造函数与常规成员方法没有什么不同。 您可以成功地使用我们已经在构造函数中讨论过的所有技术。

但是,当构造函数参数列表越来越长并且其中许多是可选参数时,应用构造函数重载似乎很麻烦。

如果您同意,则应签出Builder模式。

建造者模式

让我们考虑一个具有多个可选字段的类:

class ProgrammerProfile {// required fieldprivate final String name;// optional fieldsprivate final String blogUrl;private final String twitterHandler;private final String githubUrl;public ProgrammerProfile(String name) {Objects.requireNonNull(name);this.name = name;// other fields assignment...}// getters}

如果您创建了一个构造函数来覆盖所有可能的带有可选参数的组合,那么最终将得到一个相当庞大的清单。

如何避免多个构造函数? 使用构建器类。

您通常将构建器实现为它应该构建的类的内部类。 这样,两个类都可以访问其私有成员。

看一下前面示例中的类的构建器:

class ProgrammerProfile {// fields, getters, ...private ProgrammerProfile(Builder builder) {Objects.requireNonNull(builder.name);name = builder.name;blogUrl = builder.blogUrl;twitterHandler = builder.twitterHandler;githubUrl = builder.githubUrl;}public static Builder newBuilder() {return new Builder();}static final class Builder {private String name;private String blogUrl;private String twitterHandler;private String githubUrl;private Builder() {}public Builder withName(String val) {name = val;return this;}public Builder withBlogUrl(String val) {blogUrl = val;return this;}public Builder withTwitterHandler(String val) {twitterHandler = val;return this;}public Builder withGithubUrl(String val) {githubUrl = val;return this;}public ProgrammerProfile build() {return new ProgrammerProfile(this);}}}

代替公共构造函数,我们只为内部构建器类公开一个静态工厂方法。 专用构造函数(构建器在build()方法中调用)使用构建器实例分配所有字段并验证是否存在所有必需的值。

一想起来,这是一种非常简单的技术。

仅设置选定的可选参数的该构建器的客户机代码可能如下所示:

ProgrammerProfile.newBuilder().withName("Daniel").withBlogUrl("www.dolszewski.com/blog/").build();

使用构建器,您可以使用对象的可选参数创建所有可能的组合。

可选参数

编译时安全的类生成器

不幸的是,仅通过查看上一节中构建器的方法,您就无法真正分辨出哪些参数是可选的,哪些是必需的。 此外,在不知道您可以偶然省略必需参数的情况下。

查看以下错误使用的构建器示例

ProgrammerProfile.newBuilder().withBlogUrl("www.dolszewski.com/blog/").withTwitterHandler("daolszewski").build();

编译器不会报告任何错误。 您将仅在运行时意识到缺少必需参数的问题。

那么您如何解决这个问题?

您需要稍微修改构建器工厂方法,以便只能使用必需的参数调用它,而仅对可选参数使用左构建器方法。

这就是您要做的所有更改:

class ProgrammerProfile {// ...public static Builder newBuilder(String name) {return new Builder(name);}public static final class Builder {private final String name;// ...private Builder(String name) {this.name = name;}// ...}
}

生成器类的生成

您可能会认为构建器需要大量代码。

不用担心

您不必自己键入所有代码。 所有流行的Java IDE都具有允许生成类生成器的插件。 IntelliJ用户可以检查InnerBuilder插件 ,而Eclipse爱好者可以看看Spart Builder Generator 。 您也可以在官方存储库中找到替代插件。

如果您使用项目Lombok ,它还可以简化与类构建器的合作。 如果需要开始的地方,可以查看有关Lombok建筑商的简短介绍 。

3. Java可选参数反模式

在浏览网络以寻找使用Java可选参数的方法时,除了我们已经介绍的内容之外,您还可以找到一些其他建议。 让我解释一下为什么您应该将它们视为错误的方法。

地图

从技术上讲,方法的输入是一组键值对。 在Java中,我们有一个符合此描述的标准内置数据结构-Map。

编译不会阻止您将HashMap <String,Object>用作所有可选方法参数的容器,但是您的常识应该如此。

尽管您可以在HashMap中放入任何内容,但这是错误的想法。 这种方法难以理解,难以理解,并将Swift成为您维护的噩梦。

还是不服气?

您绝对应该考虑将您的职业转到JavaScript开发人员。 在公司哭泣要容易得多。

Java变量

需要明确的是,使用Java varargs绝对没有错。 如果您不知道您的方法将调用多少个参数,那么varargs是一个完美的选择。

但是将varargs用作单个值的容器(可能存在或不存在)是一种滥用。 这样的声明允许使用比预期更多的可选值来调用方法。 我们讨论了用于处理单个可选参数的更具描述性的方法。

为什么不将Optional作为方法参数?

最后,最具争议的方法-Java 8 Optional作为方法输入。 我已经写了一篇关于可选用例的文章 ,其中还介绍了方法参数。 让我扩展您在那里可以找到的内容。

内存使用情况

创建Optional类的实例时,必须为其分配内存。 尽管使用Optional.empty()访问的空可选实例是可重用的单例(就像我们已经讨论过的空集合一样),但非空实例将占用操作内存。

如果将此方法与其他可能性进行比较,则仅使用可选工厂方法包装对象只是为了调用将立即对其进行包装的方法是没有意义的。

但是,如今,垃圾收集器可以很好地处理短寿命的物品。 内存分配并不重要。 我们还有其他缺点吗?

可选参数

铭记读者

代码的可读性如何?

createProfile("Daniel", Optional.of("www.dolszewski.com/blog/"),Optional.of("daolszewski"), Optional.of("https://github.com/danielolszewski"));

也许这只是个人喜好问题,但对于许多开发人员而言,多个Optional工厂调用会分散您的注意力。 阅读器代码中的噪音。 但这又只是一个品味问题。 让我们找到更令人信服的东西。

可选参数

Java语言设计师的意见

甲骨文公司Java语言架构师Brian Goetz 曾表示 ,将Optional添加到标准库中时要考虑方法的结果,而不是方法的输入。

但是软件开发人员是叛逆者,不喜欢听当局的话。 这种说法似乎也很微弱。 我们必须更深入。

可选参数

Optional是否解决了可选参数问题?

如果您有这样的方法声明:

doSomethingWith(Optional<Object> parameter);

您应该期望多少输入?

该参数可以是包装值或空的可选实例。 答案是2,对吗?

错误。

真正的答案是3,因为您还可以将null用作参数。 如果您不知道谁将成为API的调用者,则对输入的信任应该有限。

在这种情况下,在处理参数之前,应检查Optional是否不等于null,然后检查该值是否存在。 非常复杂,您不同意吗?

我敢肯定我还没有穷尽这个话题。 由于这是Java编程的潜在圣战之一,因此您应该形成自己的见解。 如果要向Optional的参数列表中添加某些内容作为方法参数,请在注释中分享您的想法。 非常欢迎。

结论

让我们回顾一下我们学到的东西。 Java无法为方法参数设置默认值。 该语言为我们提供了许多其他可选参数来处理可选参数。

这些替代方法包括@Nullable批注,空对象,方法重载和参数对象模式。 我们还熟悉具有多个可选字段的对象的类构建器。 最后,我们回顾了常见的不良做法和潜在的滥用行为。

如果您觉得这篇文章对您有帮助,非常感谢与您的关注者分享。 我也很想知道您的想法,欢迎提出所有意见。

翻译自: https://www.javacodegeeks.com/2018/11/java-optional-parameters.html

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

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

相关文章

[渝粤教育] 西南科技大学 单片机原理与应用 在线考试复习资料(2)

单片机原理与应用——在线考试复习资料 一、单选题 1.信息能够同时双向传送的是( )。 A.并行通信 B.单工串行通信 C.半双工串行通信 D.全双工串行通信 2.T89S52单片机片内有( )个定时器/计数器。 A.1 B.2 C.3 D.4 3.串口通信时,每秒传送120个字符,数据格式为1位起始位、8位数…

android前台进程视频教程,Android Twilio视频通话,唤醒应用程序并进入前台

因此,我们已经找到了解决方案(当收到通知时,将应用程序置于前台),即使已经有一段时间了,我仍在发布它&#xff1a;> FCM通知(firebase云消息传递通知)只需在通知中发送“数据”.因此,通知的JSON结构中没有Notification对象,只有数据.这样,通知便由您应用的FirebaseMessaging…

[渝粤教育] 西南科技大学 土木工程施工 在线考试复习资料(1)

土木工程施工——在线考试复习资料 一、单选题 1.先张法预应力筋放张时,其混凝土应到达设计强度的( )。 A.50% B.75% C.90% D.100% 2.抹灰标志块的厚度为( )。 A.底层厚度 B.中层厚度 C.底层中层厚度 D.底层中层面层厚度 3.预应力超张拉是为了( )。 A.减少预应力筋与孔道摩擦…

[渝粤教育] 西南科技大学 审计原理与实务 在线考试复习资料2021

审计原理与实务——在线考试复习资料2021 一、单选题 1. 注册会计师在执行报表审计业务中,若发现有违法行为,应当予以( )。 A.向主管部门报告 B.拒绝审计 C.向法院起诉 D.向董事会报告 答案:看左边查询 2.注册会计师从1000个应收账款明细账…

android 日期相,Android日历始终保持相同的日期

当用户签入复选框时&#xff0c;我希望闹钟响起。这是我的代码&#xff1a;if (cb1.isChecked()){Calendar calA Calendar.getInstance();//calA.set(Calendar.YEAR, Calendar.YEAR);//calA.set(Calendar.MONTH, Calendar.MONTH);//calA.set(Calendar.DAY_OF_MONTH, Calendar.…

[渝粤教育] 西南科技大学 广告学 在线考试复习资料

广告学——在线考试复习资料 一、单选题 1.下列不属于平面广告表现形式的是( ) A.漫画 B.照片 C.广告视频 D.广告画 2.下列广告媒体出现相对最早的是( ) A.电视 B.网络 C.报纸 D.户外广告牌 3.下列不属于视觉广告的是( ) A.报纸广告 B.电视广告 C.广播广告 D.霓虹灯广告 4.在…

jedis与redis_Redis与Jedis排序

jedis与redis在本文中&#xff0c;我们将讨论Redis SORT命令。 Redis提供了SORT命令&#xff0c;我们可以使用该命令从LIST&#xff0c;SET或ZSET中检索或存储排序的值。 我们可以使用最简单的形式在KEY上使用命令&#xff0c;如下例所示&#xff1a; SORT numbers_list这将…

[渝粤教育] 西南科技大学 微机原理与应用 在线考试复习资料(1)

微机原理与应用——在线考试复习资料 一、单选题 1.十六进制数0A95转换成二进制数是? A.1010 1001 0101 B.0000 1010 0101 C.1000 1010 1001 D.0000 1110 1001 2.设BX2000H,[0003H]16H,[2000H]25H,[2003H]74H,执行指令MOV BX,2000H和指令MOV AL,[BX03H]后,AL中的数据是? A.7…

计算机发送到桌面快捷方式,windows7添加到桌面快捷方式无故消失!

您好&#xff0c;Windows 7设计者在Windows 7中所添加的设计。在默认情况下&#xff0c;只要System Maintenance troubleshooter(系统故障维护&#xff0c;以下简称SMT)检测到桌面的快捷方式已经无效了&#xff0c;将会自动将其删除。每周&#xff0c;SMT(系统故障维护)都会对操…

[渝粤教育] 西南科技大学 政府经济学 在线考试复习资料

政府经济学——在线考试复习资料 一、单选题 1.最优多数规则的优点在于( )。 A.保护每个人的平等权利 B.降低决策成本及保护少数 C.便于投票者实现利益交换 D.保护利益集团 2.不列入预算的国家财政支出称为( ) A.预算外支出 B.预算支出 C.国防支出 D.购买性支出 3.下列各组公…

Java:汇总堆外数据

探索如何以最小的垃圾收集影响和最大的内存利用率创建堆​​外聚合。 使用Java Map&#xff0c;List和Object创建大型聚合通常会产生大量堆内存开销。 这也意味着&#xff0c;一旦聚合超出范围&#xff0c;垃圾收集器将必须清理这些对象。 阅读这篇简短的文章&#xff0c;了解…

[渝粤教育] 西南科技大学 施工组织 在线考试复习资料

施工组织——在线考试复习资料 一、单选题 1.在双代号时标网络计划中,其关键线路是( )。 A.自始至终没有虚工作的线路 B.自始至终没有波形线的线路 C.既无虚工作,又无波形线的线路 D.所需资源最多的工作构成的线路 2.施工现场的道路干线应采用( )布置。 A.一字形 B.U形 C.环形…

计算机房英语单词,主机房是什么意思

1. 介绍了冷热源的选择及空调风系统、水系统、自控系统设计及主机房采取的安全措施&#xff0c;并做了几点设计总结。Presents the selection of cold and heat sources and design of the air system, water system, control system and the safety measures for main equipme…

[渝粤教育] 西南科技大学 材料力学 在线考试复习资料(1)

材料力学——在线考试复习资料 一、单选题 1.对于静定结构,若改变杆件横截面的尺寸,则 。 A.内力不变,位移不变 B.内力改变,位移不变 C.内力不变,位移改变 D.内力改变,位移改变 2.叠加原理用于求解静定结构时,需要满足的条件是 。 A.材料是理想弹性的 B.位移是微…

[渝粤教育] 西南科技大学 现代企业管理 在线考试复习资料

现代企业管理——在线考试复习资料 一、单选题 1.在企业科学管理阶段,泰勒提出的思想是( ) A.人群关系理论 B.需求层次理论 C.科学管理理论 D.双因素理论 2.产品发展期的主要特点是( ) A.销量迅速增加 B.企业利润增长慢 C.成本高、亏损严重 D.需要对产品的进退进行认真选择 3…

html引入latex,如何在html文件中使用MathJax或LaTex?

我无法让它工作&#xff0c;我不确定我做错了什么。我已经下载了MathJax.js&#xff0c;创建了一个html文件&#xff0c;并将其与js文件相关联。我甚至在此处复制并粘贴了之前已回答的问题&#xff0c;只是将vpn(vpn也没有工作&#xff0c;但问题和响应超过三年)的链接更改为我…

java中属性外部化_用Java可外部化

java中属性外部化在理解Externalizable接口之前&#xff0c;您需要了解序列化。您可以在java中的序列化上阅读有关序列化的更多信息。 Java提供了一种称为序列化的机制&#xff0c;以按字节的有序或字节序列的形式持久化Java对象&#xff0c;其中包括对象的数据以及有关对象的…

[渝粤教育] 西南科技大学 电子设计EDA 在线考试复习资料

电子设计EDA——在线考试复习资料 一、单选题 1. 执行菜单命令( ),用户可以选定某个元件,使程序只对与该元件相连的网络进行自动布线。 A.uto Routing/All B.uto Routing/Net C.uto Routing/Connection D.uto Routing/Component 2.对选中元件进行逆时针旋转,可以按( )。 A…

[渝粤教育] 西南科技大学 管理信息系统 在线考试复习资料(1)

管理信息系统——在线考试复习资料 一、单选题 1.系统转换是在( ) A.系统分析阶段 B.系统设计阶段 C.系统实施阶段 D.系统规划阶段 2.系统设计包括多项内容,下述哪一项是系统设计最基础性的工作?( ) A.代码设计 B.屏幕设计 C.输入设计 D.输出设计 3.用决策树描述处理逻辑是在…

在您的Maven-Fu包中增加了一些东西

Apache Maven很简单&#xff0c;但是功能非常强大。 使用一些技巧&#xff0c;您可以大大简化和优化您的开发经验。 处理多个非托管模块 假设您有一个主项目A提供了两个实用程序模块foo和bar &#xff0c;另一个项目B A了foo和bar 。 在使用B &#xff0c;您意识到需要偶尔对…