2

While reading up on the new features introduced in Java 8, I came across the concept of Predicates. I noticed that most of the examples provided on the internet and in books use static functions to create predicates.

Consider the following Apple class for example :

public class Apple {

    private String color;
    private int weight;

    private static final int SMALL_APPLE_MAX_WEIGHT = 150;

    public Apple(String color, int weight) {
        this.color = color;
        this.weight = weight;
    }

    public static boolean isGreenApple(Apple apple) {
        return null!=apple && null!=apple.getColor() && "green".equals(apple.getColor());
    }

    public boolean isBigApple() {
        return this.getWeight() > SMALL_APPLE_MAX_WEIGHT;
    }
}

I can now create a new predicate as follows :

Predicate<Apple> isGreenApple = Apple::isGreenApple;
Predicate<Apple> isBigApple = Apple::isBigApple;

As shown above, I can create a predicate using both a static as well as an instance method. Which approach is the preferred approach then and why?

Chetan Kinger
  • 15,069
  • 6
  • 45
  • 82
  • Why not use a lambda instead? – Makoto Jan 15 '15 at 18:15
  • I have not yet read up on lambdas. I understand lambdas will eliminate the need for creating such functions explicitly. What I am more interested in knowing is why are all examples on predicates shown using static methods? Any specific reason for not using instance methods? – Chetan Kinger Jan 15 '15 at 18:19

2 Answers2

6

For a method reference, there is no difference between an instance method A.foo() and a static method foo(A), in fact, the compiler will reject a method reference as ambiguous if both exist.

So the decision whether to use an instance method or a static method does not depend on the question whether you want to create a function via method reference for it.

Rather, you have to apply the same considerations us usual. Should the method be overridable, it has to be an instance method, otherwise, if it represents a fixed algorithm, you may consider a static method, but of course, a final method would do as well.

static methods are obviously unavoidable when you are not the maintainer of the class whose instance you want to process, in other words, when the containing class has to be different than the class of the instance. But even if the class is the same but you feel that it could be placed in another (utility) class as well, declaring it as static might be the better choice.

This holds especially when there are more than one parameter and the first one isn’t special to the operation, e.g. max(Foo,Foo) should be a static method rather than an instance method max(Foo) on Foo.

But in the end there are different programming styles out there and the answer is that method references do not mandate a particular programming style.


Regarding why there are so many examples using static methods; well I don’t know enough examples to decide whether your observation is right or just a subjective view. But maybe some tutorial writers are themselves not aware about the possibility to refer to an instance method as a function taking the method receiver as first argument.

I think, there are examples, like

Predicate<String> empty=String::isEmpty;
Predicate<CharSequence> isHello="hello"::contentEquals;

which are worth to be shown in tutorials to emphasize that you are not required to create methods specially intended to be used as method references, but that in fact there are a lot of already existing methods, static and non-static, to be directly usable with method references.

Community
  • 1
  • 1
Holger
  • 285,553
  • 42
  • 434
  • 765
1

What I am more interested in knowing is why are all examples on predicates shown using static methods?

The reference appears on the Class as no additional argument is required.

Any specific reason for not using instance methods?

For non-static methods that would make sense. In the case of

Predicate<Apple> isBigApple = Apple::isBigApple;

Predicate needs a argument so it takes this. An example of a non-method call would be something like

List<Apple> bigApples = new ArrayList<>();
apples.stream().filter(Apple::isBigApple).forEach(bigApple::add);
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130