Ich habe eine Situation festgestellt, die beim Refactoring-Code mehr oder weniger so aussah; hier aus Gründen des Beispiels neu geschrieben:Java-Konstruktor-Verkettung mit Methodenreferenz
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);
}
}
}
Dieser Code wird nicht kompiliert, weil wir cannot reference this before supertype constructor has been called
:
public UrlProbe(OkHttpClient http, String url) {
this(http, url, this::debuggingStringTransform);
}
Im Folgenden wird auch nicht kompilieren:
public UrlProbe(OkHttpClient http, String url) {
this(http, url, response -> debuggingStringTransform(response));
}
Der einzige Weg, ich Habe herausgefunden, dass dies explizit einen nicht verketteten Konstruktor verwendet:
public UrlProbe(OkHttpClient http, String url) {
this.http = http;
this.url = url;
this.transform = this::debuggingStringTransform;
}
Während es sinnvoll ist, die Verwendung von this
in Konstruktoren Verkettung von Argumenten zu beschränken, finde ich es in diesem speziellen Kontext überraschend, da es keine Art von Bewertung des Objekts zu sein scheint, verursacht durch die Verwendung von this
wenn es um Methodenreferenzen und den Inhalt eines Lambda-Ausdrucks geht.
Gibt es eine andere Begründung als JLS §8.8.7.1?
Sie können auch Methode 'debuggingStringTransform' statisch machen und statische Methodenreferenz verwenden –
@VladBochenin Die Situation, die ich bei der Arbeit hatte, war ein wenig komplexer als das, aber in meinem Beispiel' debuggingStringTransform' habe ich darauf geachtet, eine Referenz aufzunehmen zu dem Instanzfeld "url", so dass es nicht statisch sein kann – Hay
Es ist, weil Sie nicht garantieren können, dass debugginStringTransform nicht aufgerufen wird, bevor dieser oder super aufgerufen wird. Was passiert, wenn der nächste Konstruktor die Funktion aufruft, bevor Super ausgeführt wird? – jontro