Строки Java: сравнение () с равно () - PullRequest
108 голосов
/ 11 октября 2009

При тестировании на равенство String в Java я всегда использовал equals(), потому что для меня это наиболее естественный метод. В конце концов, его имя уже говорит о том, что он должен делать. Однако мой коллега недавно сказал мне, что меня научили использовать compareTo() == 0 вместо equals(). Это кажется неестественным (так как compareTo() предназначено для обеспечения порядка, а не сравнения на равенство) и даже несколько опасным (потому что compareTo() == 0 не обязательно подразумевает равенство во всех случаях, хотя я знаю, что это действительно для String ) для меня.

Он не знал, почему его научили использовать compareTo() вместо equals() для String, и я также не смог найти причину, почему. Это действительно вопрос личного вкуса, или есть какая-то реальная причина для любого метода?

Ответы [ 20 ]

96 голосов
/ 11 октября 2009

Разница в том, что "foo".equals((String)null) возвращает false, а "foo".compareTo((String)null) == 0 создает исключение NullPointerException. Так что они не всегда взаимозаменяемы даже для строк.

26 голосов
/ 11 октября 2009

2 основных различия заключаются в том, что:

  1. equals будет принимать любой объект в качестве параметра, но compareTo будет принимать только строки.
  2. equals только сообщает вам, равны они или нет, но compareTo дает информацию о том, как лексикографически сравниваются строки.

Я посмотрел на код класса String , и алгоритм внутри CompareTo и equals выглядит в основном одинаково. Я полагаю, что его мнение было только вопросом вкуса, и я согласен с вами - если вам нужно знать только равенство строк, а не то, какой из них стоит на первом месте лексикографически, я бы использовал equals.

26 голосов
/ 11 октября 2009

При сравнении на равенство вы должны использовать equals(), потому что оно четко выражает ваши намерения.

compareTo() имеет дополнительный недостаток, заключающийся в том, что он работает только с объектами, которые реализуют интерфейс Comparable.

Это относится, в общем, не только к строкам.

16 голосов
/ 11 октября 2009

compareTo выполняет больше работы, если строки имеют разную длину. equals может просто возвращать false, тогда как compareTo всегда должен проверять достаточно символов, чтобы найти порядок сортировки.

10 голосов
/ 05 августа 2010

compareTo() применяется не только к строкам, но и к любому другому объекту, поскольку compareTo<T> принимает общий аргумент T. String - это один из классов, в котором реализован метод compareTo() путем реализации интерфейса Comparable. (compareTo () - метод сопоставимого интерфейса). Таким образом, любой класс может свободно реализовать Comparable. интерфейс.

Но compareTo() дает порядок объектов , обычно используемых при сортировке объектов в порядке возрастания или убывания, в то время как equals() будет говорить только о равенстве и говорить, являются ли они равно или нет.

10 голосов
/ 07 июля 2012

в строковом контексте:
compareTo: сравнивает две строки лексикографически.
равно: Сравнивает эту строку с указанным объектом.

compareTo сравнивает две строки по их символам (с тем же индексом) и возвращает целое число (положительное или отрицательное) соответственно.

String s1 = "ab";
String s2 = "ab";
String s3 = "qb";
s1.compareTo(s2); // is 0
s1.compareTo(s3); // is -16
s3.compareTo(s1); // is 16
7 голосов
/ 28 мая 2016

равно () может быть более эффективным, чем compareTo () .

Очень важное различие между сравнить и равно:

"myString".compareTo(null);  //Throws java.lang.NullPointerException
"myString".equals(null);     //Returns false

equals () проверяет, являются ли два объекта одинаковыми или нет, и возвращает логическое значение.

compareTo () (из интерфейса Comparable) возвращает целое число. Он проверяет, какой из двух объектов «меньше», «равен» или «больше» другого. Не все объекты могут быть упорядочены логически, поэтому метод compareTo () не всегда имеет смысл.

Обратите внимание, что equals () не определяет порядок между объектами, который делает CompareTo ().

Теперь я советую вам просмотреть исходный код обоих методов, чтобы сделать вывод, что равенство предпочтительнее, чем сравнение, которое включает некоторые математические вычисления.

5 голосов
/ 15 мая 2013

equals() должен быть методом выбора в случае ОП.

Глядя на реализацию equals() и compareTo() в java.lang.String для grepcode , мы можем легко увидеть, что функция equals лучше, если мы просто заинтересованы в равенстве двух строк:

equals():

<a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1012" rel="noreferrer">1012</a>  <b>public</b> <b>boolean</b> equals(<a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Object.java#Object" rel="noreferrer" title="java.lang.Object">Object</a> anObject) {<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1013" rel="noreferrer">1013</a>      <b>if</b> (<b>this</b> == anObject) {<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1014" rel="noreferrer">1014</a>          <b>return</b> <b>true</b>;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1015" rel="noreferrer">1015</a>      }<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1016" rel="noreferrer">1016</a>      <b>if</b> (anObject <b>instanceof</b> <a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#String" rel="noreferrer" title="java.lang.String">String</a>) {<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1017" rel="noreferrer">1017</a>          <a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#String" rel="noreferrer" title="java.lang.String">String</a> anotherString = (<a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#String" rel="noreferrer" title="java.lang.String">String</a>)anObject;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1018" rel="noreferrer">1018</a>          <b>int</b> n = count;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1019" rel="noreferrer">1019</a>          <b>if</b> (n == anotherString.count) {<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1020" rel="noreferrer">1020</a>              <b>char</b> v1[] = value;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1021" rel="noreferrer">1021</a>              <b>char</b> v2[] = anotherString.value;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1022" rel="noreferrer">1022</a>              <b>int</b> i = offset;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1023" rel="noreferrer">1023</a>              <b>int</b> j = anotherString.offset;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1024" rel="noreferrer">1024</a>              <b>while</b> (n-- != 0) {<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1025" rel="noreferrer">1025</a>                  <b>if</b> (v1[i++] != v2[j++])<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1026" rel="noreferrer">1026</a>                      <b>return</b> <b>false</b>;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1027" rel="noreferrer">1027</a>              }<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1028" rel="noreferrer">1028</a>              <b>return</b> <b>true</b>;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1029" rel="noreferrer">1029</a>          }<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1030" rel="noreferrer">1030</a>      }<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1031" rel="noreferrer">1031</a>      <b>return</b> <b>false</b>;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1032" rel="noreferrer">1032</a>  }<br/>

и compareTo():

<a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1174" rel="noreferrer">1174</a>  <b>public</b> <b>int</b> compareTo(<a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#String" rel="noreferrer" title="java.lang.String">String</a> anotherString) {<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1175" rel="noreferrer">1175</a>      <b>int</b> len1 = count;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1176" rel="noreferrer">1176</a>      <b>int</b> len2 = anotherString.count;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1177" rel="noreferrer">1177</a>      <b>int</b> n = Math.<a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/Math.java#Math.min%28int%2Cint%29" rel="noreferrer" title="java.lang.Math.min(int,int) : int">min</a>(len1, len2);<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1178" rel="noreferrer">1178</a>      <b>char</b> v1[] = value;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1179" rel="noreferrer">1179</a>      <b>char</b> v2[] = anotherString.value;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1180" rel="noreferrer">1180</a>      <b>int</b> i = offset;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1181" rel="noreferrer">1181</a>      <b>int</b> j = anotherString.offset;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1183" rel="noreferrer">1183</a>      <b>if</b> (i == j) {<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1184" rel="noreferrer">1184</a>          <b>int</b> k = i;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1185" rel="noreferrer">1185</a>          <b>int</b> lim = n + i;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1186" rel="noreferrer">1186</a>          <b>while</b> (k < lim) {<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1187" rel="noreferrer">1187</a>              <b>char</b> c1 = v1[k];<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1188" rel="noreferrer">1188</a>              <b>char</b> c2 = v2[k];<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1189" rel="noreferrer">1189</a>              <b>if</b> (c1 != c2) {<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1190" rel="noreferrer">1190</a>                  <b>return</b> c1 - c2;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1191" rel="noreferrer">1191</a>              }<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1192" rel="noreferrer">1192</a>              k++;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1193" rel="noreferrer">1193</a>          }<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1194" rel="noreferrer">1194</a>      } <b>else</b> {<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1195" rel="noreferrer">1195</a>          <b>while</b> (n-- != 0) {<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1196" rel="noreferrer">1196</a>              <b>char</b> c1 = v1[i++];<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1197" rel="noreferrer">1197</a>              <b>char</b> c2 = v2[j++];<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1198" rel="noreferrer">1198</a>              <b>if</b> (c1 != c2) {<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1199" rel="noreferrer">1199</a>                  <b>return</b> c1 - c2;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1200" rel="noreferrer">1200</a>              }<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1201" rel="noreferrer">1201</a>          }<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1202" rel="noreferrer">1202</a>      }<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1203" rel="noreferrer">1203</a>      <b>return</b> len1 - len2;<br/><a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java#1204" rel="noreferrer">1204</a>  }<br/><br/>

Когда одна из строк является префиксом другой, производительность compareTo() ухудшается, поскольку все еще необходимо определить лексикографический порядок, в то время как equals() больше не будет беспокоиться и немедленно вернет false.

На мой взгляд, мы должны использовать эти два, как они были предназначены:

  • equals() для проверки на равенство и
  • compareTo() для поиска лексического порядка.
5 голосов
/ 11 октября 2009

Похоже, что оба метода в значительной степени делают одно и то же, но метод compareTo () принимает String, а не Object, и добавляет некоторые дополнительные функции поверх обычного метода equals (). Если все, что вас волнует, это равенство, то метод equals () является лучшим выбором, просто потому, что он имеет больше смысла для следующего программиста, который изучит ваш код. Разница во времени между двумя различными функциями не должна иметь значения, если вы не перебираете огромное количество элементов. CompareTo () действительно полезно, когда вам нужно знать порядок строк в коллекции или когда вам нужно знать разницу в длине между строками, которые начинаются с одинаковой последовательности символов.

источник: http://java.sun.com/javase/6/docs/api/java/lang/String.html

2 голосов
/ 03 июня 2011

String.equals() требует вызова оператора instanceof, а compareTo() - нет. Мой коллега отметил значительное падение производительности, вызванное чрезмерным числом вызовов instanceof в методе equals(), однако мой тест показал, что compareTo() только немного быстрее.

Я использовал, однако, Java 1.6. В других версиях (или других поставщиках JDK) разница может быть больше.

Тест сравнивал каждую строку в 1000 элементных массивах, повторенных 10 раз.

...