5

How exactly do you chain method references for instances with Java 8? Example:

Collections.sort(civs,Comparator.comparing(Civilization::getStrategy.getStrategLevel));

getStrategy of a Civilization instance returns a Strategy object instance which has the instance method getStrategyLevel.

Why doesn't the Comparator.comparing method return a comparator with it's functional interface implemented by the lambda expression?

3
  • 4
    Just use a lambda. Commented Nov 5, 2016 at 16:28
  • 2
    A method reference is a reference to a method. The chain "call getStrategy(), then call getStrategyLevel() on the result) is not a method, therefore it is not suitable for describing with a method reference. If you want to describe an arbitrary bag of imperative code, use a lambda; method refs are a (hopefully more readable) shorthand provided for the special case where the lambda body is a single method whose argument list matches exactly that of the target functional interface. Commented Nov 6, 2016 at 18:31
  • See also: stackoverflow.com/questions/24487805/… Commented Nov 6, 2016 at 18:31

4 Answers 4

4

In that case, you should use a lambda, you can't apply a method reference directly:

Collections.sort(civs, Collectors.comparing(c -> c.getStrategy().getStrategLevel()));

Though, there is a way to use a method reference here. Assuming that you have a class like

class CivilizationUtils {
    public static Integer getKeyExtractor(Civilization c) {
        return c.getStrategy().getStrategLevel();
    }
}

the issue could be solved like

Collections.sort(civs, Collectors.comparing(CivilizationUtils::getKeyExtractor));
Sign up to request clarification or add additional context in comments.

2 Comments

getStrategy is not a static method
how would I provide a method reference to the instance method getStrategyLevel through an instance of Strategy which is accessed through an instance of Civilization. Should I just use a regular lambda expression for the comparator?
3

You cannot do it with a method reference, you need to use a lambda expression or create a static method.

There are four kinds of method references:

  1. Reference to a static method like ContainingClass::staticMethodName
  2. Reference to an instance method of a particular object like containingObject::instanceMethodName
  3. Reference to an instance method of an arbitrary object of a particular type like ContainingType::methodName
  4. Reference to a constructor like ClassName::new

More details about method reference.

So here, with a lambda expression it would be:

Collections.sort(civs, Comparator.comparing(c -> c.getStrategy.getStrategLevel()));

Or in case you create a static method

public static int getStrategLevel(Civilization c) {
    return c.getStrategy().getStrategLevel();
}

Then your code would be:

Collections.sort(civs, Comparator.comparing(MyClass::getStrategLevel));

Comments

1
Collections.sort(civs,Comparator.comparing(civ -> civ.getStrategy().getStrategLevel()));

Comments

0

Different example, but I have a method

void m(Predicate<String> stringPredicate)

and a utility class

class Utilities {
  static boolean condition1(String s) { ... }
  static boolean condition2(String s) { ... }
  ...
}

and I wanted to invoke m with a predicate that returns true iff Utilities.condition1 returns false. The Java grammar allows me to write

m(Utilities::condition1)

but not

m(Utilities::condition1.negate())

(an unfortunate violation of referential transparency), and the compiler complained, "Java Method reference not expected here."

My workaround was to write a method

Predicate<String> not(Predicate<String> p) {
  return p;
}

and then to write the call

m(not(Utilities::condition1))

--which is allowed by the Java grammar.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.