Java构造函数链接方法引用

时间:2017-09-27 20:58:45

标签: java

在重构代码的过程中,我遇到了或多或少的情况;为了这个例子,在这里重写:

public class UrlProbe {
    private final OkHttpClient http;
    private final String url;
    private final Function<Response, Object> transform;
    private Object cachedValue;

    public UrlProbe(OkHttpClient http, String url) {
        this(http, url, this::debuggingStringTransform);
    }

    public UrlProbe(OkHttpClient http, String url, Function<Response, Object> transform) {
        this.http = http;
        this.url = url;
        this.transform = transform;
    }

    private Object debuggingStringTransform(Response response) {
        String newValue = response.body().toString();
        System.out.println("Debugging new value from url " + url + ": " + newValue);
        return newValue;
    }

    public synchronized Object probe() {
        if (cachedValue != null) {
            return cachedValue;
        }

        try (Response response = http.newCall(new Request.Builder().url(url).get().build()).execute()) {
            cachedValue = transform.apply(response);
            return cachedValue;

        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }
}

此代码无法编译,因为我们cannot reference this before supertype constructor has been called

public UrlProbe(OkHttpClient http, String url) {
    this(http, url, this::debuggingStringTransform);
}

以下内容不会编译:

public UrlProbe(OkHttpClient http, String url) {
    this(http, url, response -> debuggingStringTransform(response));
}

我发现的唯一方法是明确使用非链接构造函数:

public UrlProbe(OkHttpClient http, String url) {
    this.http = http;
    this.url = url;
    this.transform = this::debuggingStringTransform;
}

虽然限制在构造函数中使用this链接参数是有意义的,但我发现在这个特定的上下文中它令人惊讶,因为似乎没有对由于在涉及方法引用和lambda表达式的内容时使用this

这种限制背后是否存在理由,因为JLS§8.8.7.1是这样说的?

2 个答案:

答案 0 :(得分:2)

允许引用此范围尽早破坏看起来像这样的代码

public class UrlProbe {
    final String url;
    final String param2;
    public UrlProbe(String url) {
        this(url, this::debuggingStringTransform);
    }

    public UrlProbe(String url, Function<String, String> transform) {
        this(url, transform.apply("")); // <-- What should happen when url is referenced here?

    }
    public UrlProbe(String url, String param2) {
        this.url = url;
        this.param2 = param2;
    }

    private String debuggingStringTransform(String response) {
        System.out.println("Debugging new value from url " + url + ": " + response);
        return response;
    }
}

这至少是违反规则的一种方式。

答案 1 :(得分:1)

IntelliJ在工具提示中显示了为什么这段代码是&#34;坏&#34;:

enter image description here

  

无法参考&#39;这个&#39;在调用超类型构造函数之前

这是有道理的。您正在构建对象的过程中,定义的方法引用仅在实例化类之后存在。 #39; s&#34;准备好&#34;。

如果您想解决这个问题,可以将该功能更改为静态功能,因为它没有所需的状态:

public UrlProbe(OkHttpClient http, String url) {
    this(http, url, UrlProbe::debuggingStringTransform);
}

private static Object debuggingStringTransform(Response response) {
    String newValue = response.body().toString();
    System.out.println("Debugging new value from url " + url + ": " + newValue);
    return newValue;
}

...虽然不可否认看到奇怪的看到private static方法。

或者,在同一个包中存在别处这个函数,就像在这个函数底部的静态类中一样:

public UrlProbe(OkHttpClient http, String url) {
    this(http, url, Functions::debuggingStringTransform);
}

static class Functions {
    static Object debuggingStringTransform(Response response) {
        String newValue = response.body().toString();
        System.out.println("Debugging new value from url " + url + ": " + newValue);
        return newValue;
    }
}