HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Enhanced for loop

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
loopenhancedfor

Problem

I much prefer the Java enhanced for each loop, but I often find there are certain times where I need to break from a loop, take the following contrived example:

final List strings = new ArrayList<>(
    Arrays.asList(new String[] { "test", "new", "break", "notThere","last" }));

boolean found;
for(String s : strings) {
  found = s.equals("break");
  if (found) { break; }
}


Needs to be rewritten as the following to avoid the break statement:

int i;
boolean found;
for (found = false, i = 0; i < strings.size() && !found; i++) {
  found = strings.get(i).equals("break");
}


Which would you prefer to come across? I very much prefer the second format (in the case where I need to break), but I have a feeling I'm in the minority.

Edit: I do need to keep track of where the item was located.

Solution

I'd use List.indexOf(Object o). From the documentation:


Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element. More formally, returns the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))), or -1 if there is no such index.

If you need a more complex examination you still can extract out the loop to a method with multiple return statements:

public int getFirstIndexOfSomething(final List input) {
    int i = 0;        
    for (String s: input) {
        if (... check s here ...) {
            return i;
        }
        i++;
    }
    return -1;
}


If you want a really bulletproof solution you can use a custom SearchResult object to store the result and its index (if there is any result):

public class SearchResult {
    private final boolean found;
    private final int index;

    private SearchResult(final boolean found) {
        this.found = false;
        this.index = -1;
    }

    private SearchResult(final int index) {
        if (index < 0) {
            throw new IllegalArgumentException("index cannot be less than zero");
        }
        found = true;
        this.index = index;
    }

    public static SearchResult createFound(final int index) {
        return new SearchResult(index);
    }

    public static SearchResult createNotFound() {
        return new SearchResult(false);
    }

    public boolean isFound() {
        return found;
    }

    public int getIndex() {
        if (!found) {
            throw new IllegalStateException();
        }
        return index;
    }
}


Usage:

public SearchResult getFirstIndexOfSomething(final List input) {
    int i = 0;        
    for (String s: input) {
        if (... check is here ...) {
            return SearchResult.createFound(i);
        }
        i++;
    }
    return SearchResult.createNotFound();
}


It does not let client codes to get invalid indexes since the getIndex method throws an exception when the for loop do not find any result.

A more sophisticated solution is using polymorphism to separate the two states to two simpler classes with a common interface:

public interface SearchResult {

    boolean isFound();

    int getIndex();
}

public class NoResult implements SearchResult {

    public NoResult() {
    }

    @Override
    public boolean isFound() {
        return false;
    }

    @Override
    public int getIndex() {
        throw new IllegalStateException();
    }
}

public class Result implements SearchResult {

    private final int index;

    public Result(final int index) {
        if (index < 0) {
            throw new IllegalArgumentException("index cannot be less than zero");
        }
        this.index = index;
    }

    @Override
    public boolean isFound() {
        return true;
    }

    @Override
    public int getIndex() {
        return index;
    }
}


Usage:

public SearchResult getFirstIndexOfSomething(final List input) {
    int i = 0;        
    for (String s: input) {
        if (... check is here ...) {
            return new Result(i);
        }
        i++;
    }
    return new NoResult();
}

Code Snippets

public int getFirstIndexOfSomething(final List<String> input) {
    int i = 0;        
    for (String s: input) {
        if (... check s here ...) {
            return i;
        }
        i++;
    }
    return -1;
}
public class SearchResult {
    private final boolean found;
    private final int index;

    private SearchResult(final boolean found) {
        this.found = false;
        this.index = -1;
    }

    private SearchResult(final int index) {
        if (index < 0) {
            throw new IllegalArgumentException("index cannot be less than zero");
        }
        found = true;
        this.index = index;
    }

    public static SearchResult createFound(final int index) {
        return new SearchResult(index);
    }

    public static SearchResult createNotFound() {
        return new SearchResult(false);
    }

    public boolean isFound() {
        return found;
    }

    public int getIndex() {
        if (!found) {
            throw new IllegalStateException();
        }
        return index;
    }
}
public SearchResult getFirstIndexOfSomething(final List<String> input) {
    int i = 0;        
    for (String s: input) {
        if (... check is here ...) {
            return SearchResult.createFound(i);
        }
        i++;
    }
    return SearchResult.createNotFound();
}
public interface SearchResult {

    boolean isFound();

    int getIndex();
}

public class NoResult implements SearchResult {

    public NoResult() {
    }

    @Override
    public boolean isFound() {
        return false;
    }

    @Override
    public int getIndex() {
        throw new IllegalStateException();
    }
}

public class Result implements SearchResult {

    private final int index;

    public Result(final int index) {
        if (index < 0) {
            throw new IllegalArgumentException("index cannot be less than zero");
        }
        this.index = index;
    }

    @Override
    public boolean isFound() {
        return true;
    }

    @Override
    public int getIndex() {
        return index;
    }
}
public SearchResult getFirstIndexOfSomething(final List<String> input) {
    int i = 0;        
    for (String s: input) {
        if (... check is here ...) {
            return new Result(i);
        }
        i++;
    }
    return new NoResult();
}

Context

StackExchange Code Review Q#12225, answer score: 5

Revisions (0)

No revisions yet.