4

This class has three methods that do the same thing, they wait three seconds for the page to load and return true if the page has loaded.
My Question is, how do I decide which piece of code is best?
I know that Lambda is preferred above Anon classes, but why is a static nested class (pageLoaded3) not fine? According to this post it should also be suited.

public final class ExpectedConditions {

    private ExpectedConditions() {
    }

    public static ExpectedCondition<Boolean> pageLoaded1() {
        return (driver) -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return !((JavascriptExecutor) driver).executeScript("return performance.timing.loadEventEnd", new Object[0])
                    .equals("0");
        };
    }

    public static ExpectedCondition<Boolean> pageLoaded2() {
        return new ExpectedCondition<Boolean>() {
            @Override
            public Boolean apply(WebDriver driver) {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return !((JavascriptExecutor) driver)
                        .executeScript("return performance.timing.loadEventEnd", new Object[0]).equals("0");
            }
        };
    }

    public static ExpectedCondition<Boolean> pageLoaded3() {
        return new PageLoaded();
    }

    private static class PageLoaded implements ExpectedCondition<Boolean> {
        @Override
        public Boolean apply(WebDriver driver) {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return !((JavascriptExecutor) driver).executeScript("return performance.timing.loadEventEnd", new Object[0])
                    .equals("0");
        }
    }

}

This is the interface of the return type of the three methods:

public interface ExpectedCondition<T> extends Function<WebDriver, T> {}
Community
  • 1
  • 1
Yoshua Nahar
  • 1,304
  • 11
  • 28
  • 3
    Your three methods are functionally equivalent (your code will do the same thing). What makes you think that a static nested class is inappropriate? – assylias Dec 26 '16 at 11:16
  • _How do I decide which piece of code is best?_ Could you ask a bit more specifically for what your are looking for? My general answer for this kind of question is "the most readable version"... – Ivo Mori Dec 26 '16 at 11:28
  • That is my question. I know all three work, but I know that in this situation the anon class shoudn't be used. When reading about member inner classes they also explicitly say, when no outer class variables are used, use static inner class. So is there a rule or convention that also says that the static inner class should or shouldn't be used? Or is it just preference? – Yoshua Nahar Dec 26 '16 at 11:33
  • I thing the third one is most readable. But someone who likes using lambdas might say the first? – Yoshua Nahar Dec 26 '16 at 11:34
  • I would use the method you believe is simplest. Note: lambdas which are one or two lines are likes to be best. I would add a helper like `static void pause(long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }` – Peter Lawrey Dec 26 '16 at 12:03
  • None is best... avoid Thread.sleep... http://stackoverflow.com/q/15122864/6809386 – Alexander Anikin Dec 26 '16 at 12:08

1 Answers1

3

As already mentioned in the comments: The functions are equivalent. So technically, the difference is marginal. All approaches are compiled to similar bytecode. So the question about which one is the "best" can only be answered in view of the code itself. And there, different criteria may be applied.

First of all, as Peter Lawrey suggested in the comment: You could pull out the Thread.sleep call into a helper method:

private static void pause(long ms)
{
    try
    {
        Thread.sleep(ms);
    }
    catch (InterruptedException e)
    {
        Thread.currentThread().interrupt();
    }
}

Additionally, you could pull out the core functionality that is implemented there into a helper method:

private static Boolean execute(WebDriver driver)
{
    pause(3000);
    return !((JavascriptExecutor) driver)
        .executeScript("return performance.timing.loadEventEnd", new Object[0])
        .equals("0");
}

Using this method, the similarity between the given approaches becomes even more obvious: They are only different ways of calling this method! And I think that introducing such a method will have additional advantages. The method is a clear "building block", with a clear interface (and hopefully with a clear JavaDoc).

Additionally, this method will open the door for a fourth implementation - namely one that uses a method reference:

public static ExpectedCondition<Boolean> pageLoaded4()
{
    return ExpectedConditions::execute;
}

So you now have four ways of implementing the desired functionaliy:

  1. With a lambda
  2. With an anonymous class
  3. With a static innner class
  4. With a method reference

Pragmatically, one can argue about the pros and cons:

  • Approach 3, with the static innner class: This is not necessary. If the static inner class is only a wrapper to a method call, it does not serve a real purpose. It introduces a new name (PageLoaded in your case), and a new indirection in the source code - meaning that the programmer has to look up the PageLoaded class to see what it does. This might be a different story in other cases. E.g. if the PageLoaded class had additional methods or fields, but this is not the case here.

  • Approach 2, with an anonymous inner class: One could argue that an anonymous class for a functional interface is just "old-fashioned" or the "pre-Java8-way" of writing it. If the type that has to be implemented is a functional interface (i.e. has a single abstract method), then using a lambda or method reference is just shorter and more convenient, and does not have any obvious drawbacks. (Of course, this would not be possible if the type that has to be implemented had multiple abstract methods. But again, this is not the case here)

  • Approach 1, with a lambda: This is the standard way of implementing such a functional interface in Java 8. I, personally, prefer to have short lambda bodies. A lambda like the one in your question

    return (driver) -> {
        // "Many" lines of code, maybe even nested, with try-catch blocks
    };
    

    is IMHO not so readable and concise, and I usually try to keep these bodies as short as possible. In the best case, the { brackets } can be omitted - in doubt, by introducing a method that comprises the lambda body. And in this case, one can often boil it down to the last approach:

  • Approach 4, with a method reference. It may be a bit subjective, but I consider this one as the most readable. The method has the advantage of being a "building block" with a clear functionality that can be clearly specified in the JavaDocs. Moreover, you might even consider to omit the wrapping method (called pageLoaded4 above), and simply offer the method as a public one. The user, who formerly called

    ExpectedCondition<Boolean> condition = 
        ExpectedConditions::pageLoaded4();
    

    might then just use the method directly

    ExpectedCondition<Boolean> condition = 
        ExpectedConditions::execute;
    

    But this depends on the exact application pattern and the intended interface of this class. It might not be desired to expose this method directly.

Marco13
  • 53,703
  • 9
  • 80
  • 159
  • Very nice answer, I appreciate it. My problem was that I could read nowhere, that Approach 3 with the static inner class should or shouldn't be used. And you summed it up nicely. – Yoshua Nahar Dec 27 '16 at 23:36