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

Class to simplify skipping some actions on the first loop iteration

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

Problem

Often I have to skip some actions on the first (or last) loop iteration. Now I need to append some arguments to a URL and separate the arguments by the & character.

For example:

http://api.openweathermap.org/data/2.5/weather?q=London&mode=xml&cnt=7


To do so, the code looks like this:

public static String prepareUrl(String url, List arguments) {
    boolean firstIteration = true;
    StringBuilder urlBuilder = new StringBuilder(url);
    for (NameValuePair argument : arguments) {
        if (firstIteration) {
            firstIteration = false;
        } else {
            urlBuilder.append("&");
        }
        urlBuilder.append(argument.getName());
        urlBuilder.append("=");
        urlBuilder.append(argument.getValue());
    }
    return urlBuilder.toString();
}


But it's very annoying to write and a little difficult to read such code. And it's easy to make a mistake in a loop body like this.

I wrote the next class, but I need your help to name the class and its methods properly (I'm pretty bad in English). And please, criticize my code severely.

// I know that class name must be a noun.
// But I can't think of a good name.
// And it seems to me that a comparison with the blank cartridge is a good one.
public abstract class FirstCartridgeIsBlank implements Runnable {

    private boolean firstCartridge;

    public FirstCartridgeIsBlank() {
        firstCartridge = true;
    }

    public final void run() {
        if (firstCartridge) {
            firstCartridge = false;
            blankShot();
        } else {
            shot();
        }
    }

    protected void blankShot() {
        // the inheritors can override this method if they need
    }

    protected abstract void shot();

}


Now the method prepareUrl() looks like this:

```
public static String prepareUrl(String url, List arguments) {
final StringBuilder urlBuilder = new StringBuilder(url);
FirstCartridgeIsBlank appendAmpersand = new FirstCartridgeIs

Solution

Don't try to over-generalize early. This is a situation I've run into quite a few times for strings, but never anywhere else, so I would recommend you start with a string-specific solution, and only try to come up with something more general if it ever becomes necessary.

You mention String.join- is there any situation where you face this problem where String.join wouldn't solve your problem? It's quite possible that the problem you actually need to solve isn't "skipping some actions on the first loop iteration", it's "cleanly joining strings with a separator". If that's the case, then why not just reimplement String.join yourself, rather than creating your own very different way of achieving the same thing?

If you do need to generalize, then your solution could work, but its main problem is that now you're creating a class whose only purpose is to run a chunk of some arbitrary (possible private!) procedure, just because that chunk happened to follow a particular structure. If Java 6 supported functional programming, then a single class which was passed functions would have been acceptable, but the need to create a new class that inherits from FirstCartridgeIsBlank every time you want to use it seems like a design headache to me.

So I think instead of trying to create a class for this, it'd probably just be simpler to do it by extracting methods:

public static String prepareUrl(String url, List arguments) {
    boolean firstIteration = true;
    StringBuilder urlBuilder = new StringBuilder(url);
    for (NameValuePair argument : arguments) {
        String argumentString = getQueryArgument(argument.getName(), argument.getValue(), firstIteration);
        firstIteration = false;
    }

    return urlBuilder.toString();
}

private static String getQueryArgument(String name, String value, Boolean includeSeparator) {
    //...
}

Code Snippets

public static String prepareUrl(String url, List<? extends NameValuePair> arguments) {
    boolean firstIteration = true;
    StringBuilder urlBuilder = new StringBuilder(url);
    for (NameValuePair argument : arguments) {
        String argumentString = getQueryArgument(argument.getName(), argument.getValue(), firstIteration);
        firstIteration = false;
    }

    return urlBuilder.toString();
}

private static String getQueryArgument(String name, String value, Boolean includeSeparator) {
    //...
}

Context

StackExchange Code Review Q#64031, answer score: 8

Revisions (0)

No revisions yet.