58

Which of the following ways is an efficient way of determining substring containment?

if (str.indexOf("/") > -1)

or

if (str.contains("/")) 
Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
sashank
  • 1,531
  • 2
  • 13
  • 26

8 Answers8

117

Take a look at the java.lang.String source code. The contains method is implemented using a call to indexOf, so they are essentially the same.

public boolean contains(CharSequence s) {
    return indexOf(s.toString()) > -1;
}

You should use whichever method makes your code more readable. If you are checking to see if a String contains a specific substring, use contains. If you are looking for the substring's starting index, use indexOf.


Edit:

A couple of answers mention that indexOf should be preferred over contains due to the fact that contains makes an additional method call, and is thus, less efficient. This is wrong. The overhead caused by an additional method call in this case is totally insignificant. Use whichever method makes the most sense in the context of your implementation. This will make your code more readable.

Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
  • 14
    "The overhead caused by an additional method call in this case is totally insignificant." Can you explain why is this the case? Bytecode optimization? Some other reason. To a layperson, it would seem an extra layer on the call stack would make *some* difference. Juts curious as to why you say it's insignificant. Thanks. – jtravaglini Aug 22 '13 at 14:00
  • 4
    The extra additional method call is not necessarily insignificant. I'm guessing you're assuming the JIT compiler is going to inline it, but this is in no way guaranteed and not all java compilers use JIT compilation either. So a flat declaration that "This is wrong" is wrong. – Will Calderwood Dec 02 '14 at 12:08
  • 1
    What about searchind directly for a char `''`, becasuse contains makes a `toString` – Tupac Jul 04 '16 at 21:13
  • as explained overhead issue makes no sense , yes it is . but for code clarity i will prefer to use contains , but if we need "index of the first occurrence " then will going to use , indexOf – Asraful Sep 26 '18 at 11:45
  • what if we use **"if (str.contains("/"))"** in a loop with more than one million repetition? – Arash Dec 13 '18 at 05:48
28

I thought I'd take an empirical approach to this question, instead of guessing about how the overhead of the additional method call would affect the outcome. I took the indexOf benchmark from this answer, and added two benchmark methods for contains() (one that takes a string constant and another that takes a variable). I'm using the just-released 1.8.0_71 running on Windows x64.

# JMH 1.11.3 (released 8 days ago)
# VM version: JDK 1.8.0_71, VM 25.71-b15

Benchmark                           Mode  Cnt   Score   Error  Units
IndexOfTest.containsString          avgt   30  26.596 ± 0.099  ns/op
IndexOfTest.containsStringIndirect  avgt   30  28.683 ± 0.088  ns/op
IndexOfTest.indexOfChar             avgt   30  26.855 ± 0.171  ns/op
IndexOfTest.indexOfCharIndirect     avgt   30  25.833 ± 0.116  ns/op
IndexOfTest.indexOfString           avgt   30  26.192 ± 0.107  ns/op
IndexOfTest.indexOfStringIndirect   avgt   30  27.547 ± 0.152  ns/op

Note that the benchmark measurements are nanoseconds per operation. So comparing contains("z") vs. indexOf("z"), the indexOf() is very slightly faster, but by less than 0.6ns. Interestingly enough, the indirect (using the variable) has a larger difference of a little over 1ns.

I've placed the code for this benchmark on GitHub: https://github.com/tedyoung/indexof-contains-benchmark

Community
  • 1
  • 1
Ted M. Young
  • 1,052
  • 11
  • 24
6

If the goal is to determine if one String contains another, then contains() is the clear winner. It will make other developers more efficient in understanding your intent.

Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
Peter Niederwieser
  • 121,412
  • 21
  • 324
  • 259
3

Basically both are the same,

public boolean contains(CharSequence s) {
    return indexOf(s.toString()) > -1;
}

But if you want do something via the index, you can use indexOf.

I believe indexOf will be more efficient, but the difference can be ignore.

Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
Pau Kiat Wee
  • 9,485
  • 42
  • 40
2

The methods have different use, if you need to check if the String contains something then use the contains, but if you want to know where in the String it is eventually contained, use the indexOf method.

aleroot
  • 71,077
  • 30
  • 176
  • 213
2

While using str.contains("/") is clearly more readable, it's likely more efficient to use str.indexOf('/') > -1. Note that I use a character instead of a String in the indexOf call.

But this shouldn't really matter performance wise unless you are in a very tight loop.

Alexander Kjäll
  • 4,246
  • 3
  • 33
  • 57
2

For single character searches such as your example, indexOf is more efficient if the argument to indexOf is a char:

if (str.indexOf('/') > -1)
Paul Jackson
  • 2,077
  • 2
  • 19
  • 29
1

Recently I have had this problem using indexOf(): when trying to find out if a String contained spaces to replace them with something else the answer from IndexOf was: the String had no spaces, which was the wrong answer. When replaced with Contains() the answer was the right one. Go figure, because as some has said here, Contains() posts a call to IndexOf.