为什么Java String没有静态字符串操作方法?


17

Java设计人员为什么不在类中创建字符串操作方法的静态版本java.lang.String?我指的是以下方法,但是问题也可以扩展到该类中的其他非静态方法。

concat(String)                        substring(int, int)
replace(char, char)                   toLowerCase()
replace(CharSequence, CharSequence)   toLowerCase(Locale)
replaceAll(String, String)            toString()
replaceFirst(String, String)          toUpperCase()
split(String)                         toUpperCase(Locale)
split(String, int)                    trim()
substring(int)

仅使用这些方法的非静态版本会在必须调用此方法的任何地方强制进行显式 null检查。例如,简单的调用example = example.trim()会导致NullPointerException异常如果String example = null。因此,程序员必须执行以下样板空检查:

if (example != null)
    example = example.trim();
// OR:
example = (example==null) ? null : example.trim();
example = (example==null) ? null : example.substring(5);

我想如果String拥有这些方法的静态版本(也许甚至是专有方法)会更方便,它将输入字符串作为第一个参数:

example = String.trim(example);
example = String.replace(example, 'a', 'b');
example = String.substring(example, 5);

这将导致由程序员编写的更干净的代码,该代码将通过简单地返回null来自动处理null情况,而不是强迫程序员显式处理null情况。该空的回归对我来说很有意义,因为操纵一个字符串应导致字符串,而不是一个错误。

Java设计人员为什么String在用Java 1或Java 2 设计类时甚至在以后的Java版本中添加此类功能时都没有想到这一点?


17
我建议将“为什么Java设计人员不考虑X”替换为“为什么Java设计人员不赞成X”。给他们基本的信誉,不要盲目选择。
Avner Shahar-Kashtan

5
null是一种例外状态,应进行明确处理。
CodesInChaos

2
@KonradMorawski:就我个人而言,我发现严重滥用扩展方法。如果您使用的是null值,那么您将尝试在其上调用方法是什么,这只会使每个读取该代码的人感到困惑。Maybe<T>我猜这是一个类型的较差的重新实现吗?
oshi子

1
@Phoshi 必须记住扩展方法不是真正的方法,它们只是语法糖。但是我同意这是有争议的。我希望C#/ Java提供某种内置的句法null安全性,例如-Kotlin。string name = employee?.personalData?.name。就像所有这些重复if (employee != null)s 的捷径一样。相关SO问题:stackoverflow.com/questions/1196031/...
康拉德·莫拉夫斯基

2
@ADTC Erm ,您确实意识到程序无法预先预测值是否为空,对吗?-您应该以确保可以将值允许为null 的方式定义接口之间的协定。空检查到处都意味着您有程序设计问题。
Uooo 2013年

Answers:


30

空值的返回对我来说很有意义,因为操作空字符串应导致空字符串,而不是错误

好吧,这是您的意见。其他人可能会争辩说,对不包含String的null对象进行String操作是没有意义的,因此应该抛出Exception

为什么“ Java设计人员”做过或没有做过的事情很难回答。

那里已经有可以执行null安全的String操作的库,例如Apache Commons的StringUtils。如果需要,可以使用该库或类似库。


根据您的评论添加

通读注释,看来您面临的真正问题是您必须检查null所有代码。如果接口之间没有明确定义合同,这可能表明程序设计不佳。您可能想阅读在Java中避免使用“!= null”语句?


1
感谢您的反馈意见。我想真正的问题是,当这样的基本功能可以成为标准Java的一部分时,为什么我们必须依赖外部库或自制类?
ADTC

4
@ADTC让我们反过来提出一个问题:如果那里已经有很多好的库,经过了很好的测试和记录,为什么“ Java设计者”应该在语言中包含一些东西?如何定义“基本特征”是基于意见的。并非每个项目都需要某个外部库来实现“基本功能”(单元测试,模拟,日期和时间等)吗?没什么大不了的?
Uooo

处理空值的一种方法是使用Optional
Guava's

10

IMO整个“如果arg为null返回null”编写方法的方法不必要地增加了程序的循环复杂性。

早期的Java库使用return null方法,但是JDK的人总是提防带有例外的null。

随着时间的流逝,我认为后一种方法显然是赢家。

为什么?由于空字段违反了很多oo原则。您根本无法将它们视为多态类的成员。这意味着您始终必须为null编码特殊情况,因此,当您必须假设事物可以为null时,圈复杂度就会急剧上升。

为了解决您的问题,请考虑使用空对象模式,而不是依赖空字段。


2
但是String不是多态的,不是吗?以及如何对像String这样的现有类型使用null对象模式?
svick

字符串不是多态的,不。但是即使如此,您仍然想知道可以在拥有的任何字符串引用上调用实例方法。这适用于所有非空引用。字符串已经有一个空对象:空字符串。就像列表中有空列表一样。因此,问问自己,为什么空字符串不足以满足您的要求?我猜您使用空字符串来标记某些特殊情况。问问自己是否可以为该特殊情况使用单独的标志。
亚历山大·托斯林

@AlexanderTorstling:类型的字段int默认为零而不是null。从概念上讲,应该可以有一个string类型,其默认值将是一个空字符串,而不是null[这种类型可能语义上是String什么intInteger。非空string将在内部保留对堆对象的引用这一事实将是一个实现细节;没有理由它在语义上不会像原始语那样。
2013年

@supercat:同意。我认为,除非明确启用,否则最好不要为引用禁用null值。默认非空和最终字段。许多类型已经具有空行为对象
Alexander Torstling

@AlexanderTorstling:将所有类型的存储位置默认为全字节零,并且可以通过全字节副本分配结构类型,这大大简化了框架,但几乎意味着具有可变引用语义的类型必须默认为空值。但是,拥有对值类型的框架支持会很有帮助,该值类型将封装单个引用,并且可以“装箱”为该引用类型,也可以从该引用类型中取消装箱
2013年

3

并不是说这是原因,但是除了toString之外,所有这些方法都可以轻松地封装在静态帮助器类中,而反之则不成立。

也就是说,如果您想要Stings.toUpper(string input)的代码很容易编写,但是如果您想要instance.toUpper,而您只有String.toUpper,那是不可能的……除非他们引入了扩展方法,当时甚至没有考虑过。


好点,虽然评论多于答案。但是即使如此,当这种基本功能可以成为标准Java的一部分时,为什么还要依赖外部库或自制类呢?
ADTC

2
截至目前,您已经拥有String.format(静态),但您还没有"something %s".format(id)
Konrad Morawski

@adtc:因为这不是通过静态类进行操作的语言的基本功能。从这个前提开始,有很多理由不这样做-不必要的代码/代码膨胀,重复的功能,开发/维护成本。
jmoreno 2013年

-2

在Java中,该字符串是一个对象。那是设计选择。

对象引用可以为null,如果没有分配对象,则为null。如果调用此类对象,则会引发NullPointerException。这是标准的oo行为。

Java设计人员选择将字符串作为对象,然后让那些方法抛出空指针异常,这是您希望字符串成为对象的结果。

为什么Java设计人员在用Java 1或Java 2设计String类时,甚至在以后的Java版本中添加这种功能时,都没有想到这一点?

他们可能确实考虑了这一点,并选择合并oo行为。


我是否可以知道,如何创建静态方法来处理null情况而不是OO行为?明确地说,我并不是说是这样,而是试图理解为什么您说设计决策要考虑OO行为。
ADTC

静态方法更像函数。对于您想要的用途,它们甚至不应该成为字符串类的一部分,而应该成为某些实用程序类的一部分。就像数学类函数一样。
Pieter B

4
仅仅因为字符串是对象并不意味着String类不能具有静态方法。而且确实已经有了一些,例如。String.format。(顺便说一句,C#中也是如此)。因此,如果这是一种设计选择,那么它不能仅基于字符串是对象这一事实,并且不能始终如一地应用。
Konrad Morawski 2013年

@PieterB如果在Strings实用程序类中至少提供了此类方法,例如我们拥有Arrays实用程序类,我不会抱怨(尽管我知道它是出于纯粹的必要性而创建的,因为数组是原始体和对象之间某种奇怪的交叉: ))..,只要它是标准Java的一部分并且不需要依赖项即可。
ADTC
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.