我想询问有关在Java中将字符串与空字符串进行比较的问题。如果我使用==
或equals
来比较一个字符串和空字符串,是否会有区别?例如:
String s1 = "hi";
if (s1 == "")
或者if (s1.equals(""))
我知道在比较字符串(或者一般的对象)时应该使用equals
而不是==
,但我想知道这对空字符串有没有影响。
我想询问有关在Java中将字符串与空字符串进行比较的问题。如果我使用==
或equals
来比较一个字符串和空字符串,是否会有区别?例如:
String s1 = "hi";
if (s1 == "")
或者if (s1.equals(""))
我知道在比较字符串(或者一般的对象)时应该使用equals
而不是==
,但我想知道这对空字符串有没有影响。
s1 == ""
它不可靠,因为它测试的是引用相等性而非对象相等性(并且String并非严格规范化)。
s1.equals("")
虽然更好,但也可能出现空指针异常。更好的选择是:
"".equals(s1)
没有空指针异常。
编辑:好的,关于规范形式的问题已经被问到。本文将其定义为:
假设我们有一些对象的集合S, 其中包含等价关系。规范形式是通过指定 S的某些对象作为“规范形式”,使得每个考虑中的对象都等价于恰好 一个规范形式对象。
给你一个实际的例子:取有理数集(或通常称为“分数”). 一个有理数由一个分子和一个分母(除数)组成,两者都是整数。这些有理数是等价的:
3/2, 6/4, 24/16
有理数通常写成最大公约数(gcd)为1的形式。所以它们都会简化为3/2。3/2可以看作是这组有理数的规范形式。
那么在编程中使用“规范形式”这个术语意味着什么?它可能有几种含义。例如,考虑以下虚构类:
public class MyInt {
private final int number;
public MyInt(int number) { this.number = number; }
public int hashCode() { return number; }
}
类MyInt的哈希码是该类的规范形式,因为对于MyInt的所有实例集合,您可以取任意两个元素m1和m2,它们将遵守以下关系:
m1.equals(m2) == (m1.hashCode() == m2.hashCode())
关系是规范形式的本质。这种情况更常见的出现方式是当您在类上使用工厂方法时,例如:
public class MyClass {
private MyClass() { }
public MyClass getInstance(...) { ... }
}
(s1 == s2) == s1.equals(s2)
当我说字符串不是严格规范的时候,这意味着:
String s1 = "blah";
String s2 = "blah";
System.out.println(s1 == s2); // true
但是正如其他人指出的那样,您可以通过使用以下方法进行更改:
String s3 = new String("blah");
可能还包括:
String s4 = String.intern("blah");
所以你不能完全依赖引用相等性,因此你不应该完全依赖它。
作为上述模式的警告,我应该指出,使用私有构造函数和工厂方法控制对象创建并不能保证引用相等性意味着对象相等,因为序列化会绕过正常的对象创建机制。Josh Bloch在Effective Java中涵盖了这个主题(最初是在第一版中讨论类型安全的枚举模式,后来成为Java 5中的语言特性),你可以通过重载(私有)readResolve()方法来解决它,但这很棘手,类加载器也会影响这个问题。
总之,这就是规范形式。
"".equals(s1)
进行测试也会在 s1
为 NULL
时返回 TRUE
。如果要将 s1
用作字符串对象,则必须单独进行测试。 - SimonSimCity"".equals(null)
返回 false
。你是不是想说 !"".equals(null)
返回 true
? - LoPoBo这将取决于字符串是否为文字。如果您使用单引号或双引号创建字符串,则可以执行以下操作:
var str = '这是一个字符串';
var str = "这是一个字符串";
如果您使用模板字符串,则需要使用反引号(`):
var str = `这是一个模板字符串`;
new String("")
String one = "";
String two = new String("");
System.out.println("one == \"\": " + (one == ""));
System.out.println("one.equals(\"\"): " + one.equals(""));
System.out.println("two == \"\": " + (two == ""));
System.out.println("two.equals(\"\"): " + two.equals(""));
--
one == "": true
one.equals(""): true
two == "": false
two.equals(""): true
简短回答
s1 == "" // No!
s1.equals("") // Ok
s1.isEmpty() // Ok: fast (from Java 1.6)
"".equals(s1) // Ok: null safe
我会确保s1不为空并使用isEmpty()。
注意:空字符串""不是特殊的字符串,但会被视为其他任何“值”。
稍微长一些的答案
对于String对象的引用取决于它们的创建方式:
使用运算符new创建的String对象总是引用不同的对象,即使它们存储相同的字符序列,因此:
String s1 = new String("");
String s2 = new String("");
s1 == s2 // false
使用等号=后跟双引号"value"括起来的值创建的字符串对象被存储在一个字符串对象池中: 在池中创建新对象之前,会搜索具有相同值的对象,如果找到则引用该对象。
String s1 = ""; // "" added to the pool
String s2 = ""; // found "" in the pool, s2 will reference the same object of s1
s1 == s2 // true
对于用双引号 ("value") 包含一个值创建的字符串同样适用:
String s1 = "";
s1 == ""; //true
String的equals方法会检查两个参数是否相等,因此写成以下这样是安全的:
s1.equals("");
如果s1 == null,这个表达式可能会抛出一个NullPointerException异常,因此,如果您在之前没有检查null值,更安全的写法是:
"".equals(s1);
请也阅读如何在Java中比较字符串?
希望这可以帮助那些可能觉得其他答案有点复杂的不太有经验的用户。 :)
这有点偏离你原来的问题,但总有办法。
if(s1.length() == 0)
我认为这与1.6版本中的isEmpty()方法相同。
"".equals(s)
看起来这是最好的选择,但是Apache commons lang库中也包含Stringutils.isEmpty(s)
""
可能是除了空字符串之外的任何东西,但却认为 isEmpty
不能被打破呢?一个害怕编写任何代码的开发者害怕自己的影子,并且有一天会发现当他们必须编写代码时不知道该怎么做。 - Peter Lawrey无论是空字符串还是非空字符串,字符串就是字符串。使用 equals()
方法。
如果您需要进行null检查,请使用String.isEmpty()或StringUtils.isEmpty(String str)。
通过使用isEquals()方法与空字符串和String进行比较。
通过使用另一个方法CompareTo()方法。
给定两个字符串:
String s1 = "abc";
String s2 = "abc";
-或者-
String s1 = new String("abc");
String s2 = new String("abc");
在两个对象上执行的 == 运算符检查对象标识(如果两个运算符返回到同一对象实例,则返回 true)。应用于 java.lang.Strings 的 == 的实际行为似乎并不总是一致的,因为存在字符串池。
在 Java 中,字符串被 interned(至少部分由 JVM 自行决定)。在任何时候,s1 和 s2 可能已经被 interned 为相同的对象引用(假设它们具有相同的值)。因此,s1 == s2
可能会返回 true 或 false,仅取决于 s1 和 s2 是否都已被 interned。
使 s1 和 s2 等于空字符串对此没有影响 - 它们仍然可能已经被 interned 或未被 interned。
简而言之,如果 s1 和 s2 具有相同的内容,则 == 可能会返回 true 或 false。如果 s1 和 s2 具有相同的内容,则 s1.equals(s2) 保证返回 true。
String.java
的equals
方法有几个优化:1:引用==
比较,2:在强制转换之前进行instanceof String
检查,以及3:在最终逐个比较字符串字符之前进行长度值比较。所以回答你的问题,是的,长度比较是有效的,但你的代码应该依赖于String.equals而不是重新发明任何轮子。 - Patrick M.isEmpty()
方法,它“仅在length()
为0时返回true”。但是你仍然需要进行空值检查,这就是为什么我真的更喜欢C#的public static bool IsNullOrEmpty
。 - Patrick M