1

I came across code like below several times:

for (char c : s.toCharArray()) {
    ....
}

I'm wondering if s.toCharArray() only excuted once or excuted s.length times? And what about the case below?

for (int i = 0; i < s.toCharArray().length; i++) {
    ....
}

Inspired by comments, did some test:

Case 1: excution time : 692.664

    String s = "dfsdfjglsdlghsl";
    for(int i = 0 ; i < 25; i++){
        s += s;
    }
    long start_time = System.nanoTime();

    for(char c : s.toCharArray()){
        int i = 0;
    }

    long end_time = System.nanoTime();
    double excution_time = (end_time - start_time)/1e6;
    System.out.println(excution_time);

Case 2: excution time : 688.217

    String s = "dfsdfjglsdlghsl";
    for(int i = 0 ; i < 25; i++){
        s += s;
    }
    long start_time = System.nanoTime();

    char[] carrays = s.toCharArray();
    for(char c : carrays){
        int i = 0;
    }

    long end_time = System.nanoTime();
    double excution_time = (end_time - start_time)/1e6;
    System.out.println(excution_time);

Almost the same. So, s.toCharArray() should only be excuted once in the first case.

zonyang
  • 828
  • 3
  • 10
  • 24
  • 6
    It's only executed once. You can find the equivalent basic for loop for the enhanced for loop [in JLS](https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.14.2) (search for "Otherwise, the Expression necessarily has an array type, T[]."). – Andy Turner Aug 10 '16 at 20:46
  • In your second example, `s.toCharArray().length` is invoked on each execution of the loop. That's unfortunate, because it copies the string into a new array each time, making this for loop at least quadratic in the string length. It's also functionally equivalent to the constant time expression `s.length()`; I'd recommend the latter. – Andy Turner Aug 10 '16 at 20:49
  • +1 for Any's comment, which I suppose can be turned into an answer. My comment is: execute this in the debugger and set a breakpoint to observe Andy's claims. – Amir Afghani Aug 10 '16 at 20:53
  • And [how a regular for statement works](http://stackoverflow.com/questions/7081339/how-does-a-for-loop-work-specifically-for). – Sotirios Delimanolis Aug 11 '16 at 01:03

1 Answers1

4

According to JLS Sec 14.14.2, an enhanced for statement over an array type:

L1: L2: ... Lm:
for ({VariableModifier} TargetType Identifier : Expression) {
  Statement
}

is equivalent to the following basic for statement:

T[] #a = Expression;
L1: L2: ... Lm:
for (int #i = 0; #i < #a.length; #i++) {
    {VariableModifier} TargetType Identifier = #a[#i];
    Statement
}

So:

for (char c : s.toCharArray()) {
  // ...
}

is equivalent to:

T[] cs = s.toCharArray();
for (int i = 0; i < cs.length; i++) {
    char c = cs[i];
    // ...
}

So the s.toCharArray() is executed only once.

However, in

for (int i = 0; i < s.toCharArray().length; i++) {

the s.toCharArray() is executed before every iteration of the loop. This is not desirable, since it creates a new array of length s.length(), copies the chars into that array, then takes the length of the array and discards the data.

Since the loop executes s.length() times, this loop is then at least quadratic in the string length.

It's much computationally cheaper to use:

for (int i = 0; i < s.length(); i++) {

which is linear in the string length.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243