Create non-capturing method reference which will call superclass method

I’m trying to refactor the following code:

class Base {
  private Object a, b, <...>; // there's like 10 of these attributes of different type

  public Object a() {
    return a;
  }
  public Object b() {
    return b;
  }
  // more getters like the ones above
}

class RootNode extends Base { }

class BranchNode extends Base {
  private RootNode root; // passed via constructor

  public Object a() {
    Object value = super.a();
    return value != null ? value : root.a();
  }
  public Object b() {
    Object value = super.b();
    return value != null ? value : root.b();
  }
  // below are more methods like the above one, all with same logic
}

Naturally, I want to remove the repetition in this code to save myself from typing even more of the same lines when new properties are added, but I cannot quite figure out how to do that.

My first instinct was that it looks a lot like this code (which, unfortunately, does not compile):

private <T> T nvlGet(Function<Base, T> accessor) {
  T value = accessor.apply(super); // this is the problem line, because there is no way to pass a "super-reference" to anything
  return value != null ? value : accessor.apply(root);
}

// and then public accessors would look like this:
public Object a() {
  return nvlGet(Base::a);
}

I can’t obviously “fix” the above code by calling accessor.apply(this) instead of accessor.apply(super), because that would cause a Stack Overflow error.

Closest I managed to come up with so far is using bound suppliers, like this:

private <T> T nvlGet(Supplier<T> first, Supplier<T> second) {
  T value = first.get();
  return value != null ? value : second.get();
}
public Object a() {
  return nvlGet(super::a, root::a);
}

However, that is two times as many references to same method than I’d like to have in ideal world. So, I would like to know if I’m missing something, and I can still somehow fix the version which uses Function<Base, T>

Solution:

There is no such thing as a “super reference” that would alter the outcome of an ordinary invocation of an overridable method (aka invokevirtual instruction).

Your solution using two method references is the best you can get, as long as you insist on using functions, whereas passing evaluated values is even simpler:

private <T> T nvlGet(T value, Supplier<T> second) {
  return value != null? value: second.get();
}
public Object a() {
  return nvlGet(super.a(), root::a);
}

method reference for instance method from static method

Sorry for not clearly the title, i’m still new to this and even English.

Collections.sort(aList, (s1, s2) -> Float.compare(s1.getAFloat(), s2.getAFloat()));

As above, can I use method references? if s1 and s2 are Floats and they don’t use get-a-float method then things become easier:

Collections.sort(aList,Float::compare);

But with s1.getAFloat() I don’t know how to use method reference or even possible to use it, thanks for answer!

Solution:

No you can’t. Look into the following code.

List<Float> aList = Arrays.asList(5.2f, 9.7f);
Collections.sort(aList, (s1, s2) -> Float.compare(s1, s2));
Collections.sort(aList, Float::compare);

If your list elements were directly of Float type then you would have used method-reference.

If elements are not of Float type then you can do like this.

List<String> aList2 = Arrays.asList("5.2f", "9.7f");  
aList2.stream().map(Float::valueOf).sorted(Float::compare)
                 .collect(Collectors.toList());

Replace lambda with method reference in flatMap during array mapping

Say we have a Customer class:

public class Customer {
    private Car[] cars;
    // getter, setter, constructor
}

and collection of customers which we need to map on cars.

Currently I’m doing it somehow like this:

Collection<Customer> customers = ...
customers.stream().flatMap(
        customer -> Arrays.stream(customer.getCars())
)...

It works well, but the code doesn’t look elegant. I’d really like to replace it with code that uses method references which usually looks more readable and more compact. But using a field of array type makes it hard.

Question: is there any way of enhancing the flatMap call so it will be more readable/compact/clear?

Solution:

You can split the flatMap call into two calls – map and flatMap – each receiving a method reference:

Collection<Customer> customers = ...
customers.stream()
         .map(Customer::getCars)
         .flatMap(Arrays::stream)...