3

I would like to make Map values resolvement lazy, so was thinking about providing a Supplier with a toString function. But below code does not compile:

A default method cannot override a method from java.lang.Object

Anyone an idea how to solve this in a neat way?

@FunctionalInterface
private static interface ToStringSupplier extends Supplier<String>
{
    default public String toString() {
        return get();
    }
}

The reason I want this is that my consumers (which are in another repository) first can update their code:

From:

String value = (Strint)map.get(key);

To:

String value = map.get(key).toString();

After which I can change the implementation to a lazy approach:

From:

String value = expensiveCalculation();
map.put(key,value);

To:

Supplier<String> supplier () -> expensiveCalculation();
map.put(key, supplier);
wdk
  • 373
  • 2
  • 8
  • It is unclear what do requirements do you have to your lazy resolvement? You can simply call get() by itself in lazy manner in upper code. Give us idea what is going around this code. What you want to get with lazy resolvement? – sphinks Nov 19 '15 at 15:30
  • Your question is unclear. Please add code that demonstrates how you would like to use a Supplier with a Map value. – VGR Nov 19 '15 at 15:42
  • Updated question with explanation why/how I want it. – wdk Nov 19 '15 at 18:40
  • You can do this with an abstract class, but not an interface. You _cannot_ attach a default `toString()` implementation to a lambda. – Louis Wasserman Nov 19 '15 at 18:57
  • @LouisWasserman: Can you give example of the abstract class solution? – wdk Nov 20 '15 at 20:42

3 Answers3

2

I found below code working fine for my problem:

private static Object getToString(Supplier<String> s) {
    return new Object()
    {
        @Override
        public String toString() {
            return s.get();
        }
    };
}

Supplier<String> supplier = () -> expensiveCalculation();
map.put(key, getToString(supplier));
wdk
  • 373
  • 2
  • 8
1

As Louis Wasserman mentioned in the comments section of the question, it is not possible to override an instance method with a default one. It can be done with a new class that delegates the #toString call to the #get method of the provided supplier.

Here's how it can be done:

import java.util.Map;
import java.util.function.Supplier;

class Scratch {

    public static final class ToStringSupplier implements Supplier<String> {

        private final Supplier<String> supplier;

        public ToStringSupplier(Supplier<String> supplier) {
            if (supplier == null) {
                throw new NullPointerException();
            }
            this.supplier = supplier;
        }

        @Override
        public String toString() {
            System.out.println("Invoked ToStringSupplier#toString.");
            return get();
        }

        @Override
        public String get() {
            System.out.println("Invoked ToStringSupplier#get.");
            return supplier.get();
        }
    }

    public static void main(String[] args) {
        final var supplier = new ToStringSupplier(() -> {
            System.out.println("Invoked Supplier#get.");
            return "The result of calculations.";
        });
        final var key = "key";
        final var map = Map.of(key, supplier);

        System.out.println("The map has been built.");
        final var calculationResult = map.get(key).toString();
        System.out.println(calculationResult);

        System.out.flush();
    }
}

The output is:

The map has been built.
Invoked ToStringSupplier#toString.
Invoked ToStringSupplier#get.
Invoked Supplier#get.
The result of calculations.
Pavel
  • 4,912
  • 7
  • 49
  • 69
-5

default is a reserved word use in switch statements

You probably want to use abstract

  • 2
    In java 8 methods in interfaces can be default and have implementation – VDanyliuk Nov 19 '15 at 15:29
  • Ok, I didn't use Java 8. It doesn't answer the how, but the why : http://stackoverflow.com/questions/24016962/java8-why-is-it-forbidden-to-define-a-default-method-for-a-method-from-java-lan – Nicolas Lefebvre Nov 19 '15 at 15:35