Mit Anmerkungen, um sicherzustellen, dass der Rückgabewert der Methode wird nicht verworfen
String
in Java unveränderlich ist. Der folgende Codeausschnitt ist, grob gesagt, "falsch".
String s = "hello world!";
s.toUpperCase(); //"wrong"!!
System.out.println(s); //still "hello world!"!!!
Obwohl dies "falsch" ist, wird der code kompiliert und ausgeführt wird, vielleicht, um die Verwirrung der viele Anfänger, die muss entweder gesagt werden, was der Fehler ist, oder für sich selbst heraus finden, indem wir die Dokumentation.
Lesen der Dokumentation ist ein wesentlicher Teil des Verstehens eine API, aber ich Frage mich, ob dies kann ergänzt werden durch zusätzliche compile-Zeit überprüft. Insbesondere Frage ich mich, ob vielleicht die Java-annotation framework kann verwendet werden, um zu erzwingen, dass der Wert, der zurückgegeben wird, indem Sie bestimmte Methoden nicht ignoriert werden. API-Designer/Bibliothek-Autoren wäre, dann verwenden Sie diese Anmerkung in Ihre Methoden zu dokumentieren, die Werte zurückgeben, sollten Sie nicht ignoriert werden.
Sobald die API wird ergänzt mit dieser annotation (oder vielleicht ein anderer Mechanismus), dann, wenn ein Benutzer schreibt einen code wie oben, es würde nicht kompiliert (oder so tun, mit eine ernste Warnung).
So kann dies getan werden, und wie würden Sie gehen über das tun so etwas?
Anhang: Die Motivation
Scheint es klar, dass im Allgemeinen Fall, Java sollte ermöglichen, Rückgabewerte von Methoden, um ignoriert zu werden. Die Rückgabewerte von Methoden wie Liste.add
(immer true
), System.setProperty
(vorherigen Wert), kann wohl getrost ignoriert werden die meisten der Zeit.
Allerdings gibt es auch viele Methoden, deren Rückgabewerte sollten NICHT ignoriert werden. Dabei ist fast immer ein Programmierer Fehler, oder sonst nicht ordnungsgemäße Verwendung der API. Diese beinhaltet Dinge wie:
- Methoden auf unveränderliche Typen (z.B.
String
,BigInteger
, etc), die Rückkehr der Ergebnis von Operationen statt mutierend der Instanz aufgerufen wird. - Methoden, deren Rückgabewert ist ein wichtiger Teil seines Verhaltens und sollte nicht ignoriert werden, aber manche Leute tun es trotzdem (z.B.
InputStream.read(byte[])
gibt die Anzahl der bytes gelesen, welche sollte NICHT davon ausgegangen, dass die gesamte Länge des array)
Derzeit können wir schreiben codes ignoriert, dass diese Werte zurückgeben und Sie kompilieren und ausführen, ohne Warnung. Statische Analyse-Steine - /bug-Finder/Stil Vollstrecker/etc. kann fast sicher Kennzeichnen Sie diese als möglich, code smells, aber es scheint angemessen zu sein/ideal, wenn dies durchgesetzt werden kann, die von der API selbst, vielleicht durch Anmerkungen.
Ist es fast unmöglich für eine Klasse, um sicherzustellen, dass es wird immer dann verwendet, "richtig", aber es gibt Dinge, die Sie tun können, um zu helfen, Kunden auf die richtige Nutzung an (siehe: Effektive Java 2nd Edition, Item 58: Verwenden Sie überprüft die Ausnahmen für die erzielbaren Konditionen und Laufzeit-exceptions für Fehler in der Programmierung und Punkt 62: Dokumentieren Sie alle Ausnahmen, die durch jede Methode). Eine Anmerkung, die durchsetzen würde Kunden nicht ignorieren Rückgabewerte von bestimmten Methoden ist, und es wird verstärkt durch den compiler zur compile-time entweder in form von Fehlern oder Warnungen, scheint im Einklang mit dieser Idee.
Anhang 2: Snippet
Das folgende ist eine vorläufige Versuch, kurz und bündig zeigt, was ich erreichen möchte:
@interface Undiscardable { }
//attachable to methods to indicate that its
//return value must not be discarded
public class UndiscardableTest {
public static @Undiscardable int f() {
return 42;
}
public static void main(String[] args) {
f(); //what do I have to do so this generates
//compilation warning/error?
System.out.println(f()); //this one would be fine!
}
}
Der obige code kompiliert und läuft einwandfrei (wie gesehen auf ideone.com). Wie kann ich es machen das es nicht so? Wie kann ich das zuweisen der Semantik möchte ich @Undiscardable
?
- OK, ich habe gerade untersuchte, ein wenig über
@Nullable/NotNull
annotation, und das scheint Recht ähnlich zu sein im Geist mit dem, was ich tun will, also das muss machbar sein: jetbrains.com/idea/documentation/howto.html ("IntelliJ IDEA warnt Sie, wenn diese Verträge verletzt werden.") - Dieser link kann hilfreich sein: JDT-APT für Eclipse, mit tutorials eclipse.org/jdt/apt/index.html
- Undiscardable ist eine schlechte Namenswahl. Diese Methoden Idempotent sind. Zusätzlich zu Ihrem Undiscardable check, der compiler könnte optimiert werden einige for-Schleifen, wenn Sie wüsste, welche Methoden wurden idempotent.
InputStream.read
ist nicht idempotent. Dies ist nicht wirklich über compiler-Optimierung, aber, wie Sie schreiben, benutzerfreundliche API.- es ist ein Fall für verwerfen einige InputStream.Lesen. wenn u r interessiert nur die letzten bytes des Streams, u haben, um noch zu Lesen der ersten bytes. Wenn Sie keine Verwendung der ersten bytes, warum nicht werfen Sie?
InputStream.read(byte[])
nicht immer füllen des Puffers. Sie muß nicht verwerfen, ist der zurückgegebene Wert, der Ihnen sagt, wie viele bytes wurden tatsächlich gelesen.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sie könnten auch check out jsr305 es definiert eine @CheckReturnValue annotation. Es ist kompatibel mit findbugs und generiert eine Warnung, wenn jemand vergisst zu verarbeiten den Rückgabewert.
Guaven-Splitter verwendet es:
http://code.google.com/p/guava-libraries/source/browse/guava/src/com/google/common/base/Splitter.java
Muss ich sagen, dass ich lieben Anmerkungen, kann guide statische code-Analyse.
Ich bin mir nicht sicher, ob der Durchführbarkeit, insbesondere in einer tragbaren Weise - aber haben Sie einen Blick auf
Römische Ziffern, in unserem Java(GitHub-code) von Adrian Kuhn. Er verwendet annotation processing UND Sonnejavac
private-API fügt römischen Ziffern Literale in Java durch den Besuch der source-code zu tun, einige Ersatz.Vielleicht könnten Sie einen ähnlichen Ansatz:
Und verpassen Sie nicht die folgenden Ressourcen aus Adrian ' s post:
Referenz
Römische Ziffern, in unserem JavaFragen
@Undiscardable
Rückgabewert ist grammatikalisch ein ExpressionStatement oder nicht (java.sun.com/docs/books/jls/third_edition/html/...). Wenn es ist, dann heben Sie die Warnung.foo(f())
?@Override visitExpressionStatement
überprüfen, ob es eine Methode Aufruf zu einer@Undiscardable
. Wenn dem so ist, erhöhen Warnung.In eine Mutter: Sie möchte einen
@Deprecated
wie annotation, die helfen würde, der compiler/IDE zu warnen/Fehler, wenn die Methode aufgerufen wurde, ohne ihm sein Ergebnis? Sie nicht erreichen können ohne änderung der Java-Quellcode und den compiler. Die Besondere Methode annotiert werden und der compiler muss sich bewusst sein, von Ihnen. Ohne änderung der Quell-und/oder compiler, können Sie die am höchsten erstellen Sie eine Art von IDE-plugin/Einstellung, die anerkennt, die Fälle und erzeugt eine Fehlermeldung/Warnung entsprechend.Update: Sie schreiben, könnte ein framework/plugin herum, das prüft die aufgerufene Methode und die Fehler entsprechend. Sie würde nur zu gerne die annotation während der Laufzeit. Dies kann durch Annotation der annotation mit
@Retention
(RetentionPolicy.LAUFZEIT)
. Anschließend können SieMethode getAnnotation()
, um zu bestimmen, wenn diese annotation verfügbar ist. Hier ist ein kickoff Beispiel, wie ein solcher Rahmen könnte diesen job:Dann noch, um dem compiler die Arbeit zu tun, anstatt, Sie zu tun, ein bisschen mehr Arbeit.
java.lang.Override
und ich habe keine Ahnung, wie das funktioniert.java.lang
Anmerkungen sind syntaktischer Zucker. Der compiler prüft, für diese Anmerkungen. Siehe auch JLS 9.6.1 - Vordefinierte Annotation-Typen.@Nullable/NotNull
sind eng miteinander verwandt, was ich tun will, so sollte ich wohl schauen in diese Richtung.@Nullable
und so weiter sind nur "Reine" Metadaten Anmerkungen. Sie sind von der gescannten framework/API während der Laufzeit (also nicht während der compile-Zeit!). Diejava.lang
sind mehr als nur die Metadaten. Sie haben eine Besondere Bedeutung durch den compiler.@NotNull/Nullable
] Verträge verletzt werden." - dies scheint zu zeigen, dass in der Tat ist es verarbeitet während der compile-Zeit, bin ich falsch?Auf Android, die Sie verwenden können
@CheckResult
zeigen eine Warnung an, wenn Rückgabewert nicht verwendet wird.Dadurch wird die Ausgabe einer Warnung:
Wenn mit RxJava, können Sie auch
@CheckReturnValue
.Müssen Sie nicht definieren einer annotation. Definieren Sie eine Regel, wenn eine Methode aufgerufen wird:
Könnten Sie implementieren einen Prozessor, erzwingt diese Regel oder implementieren Sie eine Checkstyle, erzwingt diese Regel.
apt
) von Java 5 ist veraltet. Anmerkung die Verarbeitung ist definitiv nicht (die Sie gerade nicht brauchenapt
,javac
Sie laufen).Disclaimer: Tatsächlich, ich habe die gleiche Frage und noch keine vollständige Lösung. ABER:
Ich habe eine Idee, wie dieses getan werden könnte, in eine saubere Art und Weise, die ich will, hier zu posten, während Sie versuchen, es zu tun bekommen:
Kann man mit AspectJ zum aufrufen von code nach einer bestimmten Methode aufgerufen wurde. Zum Beispiel
verwendet werden könnte. Der Rückgabe-Wert x übergeben wird, um Ihre Methode.
Ihre Methode könnte dann sehen, die für den reference count der Wert zurück. Wenn der return-Wert ist Garbadge Gesammelt, es wurde weggeworfen, und Sie könnte eine Warnung ausgeben, siehe, z.B.,
http://java.dzone.com/articles/letting-garbage-collector-do-c
Natürlich, ich würde es vorziehen, eine Anmerkung, und compile-Zeit-Unterstützung für diese, da oben ist vielleicht nur geeignet in einer Testumgebung und vielleicht nicht in der Produktion (wegen seiner Auswirkungen auf die Leistung).
Kommentare, wenn das funktionieren könnte?
Hast du ein problem und das problem ist, dass die Menschen können versehentlich vergessen die Verwendung der Renditen von Methoden. Durch die Verwendung von Anmerkungen, die Sie sagen, sind die Bibliothek-Schreiber, Sie müssen die Verantwortung für die Erinnerung Ihre Anrufer nicht wegwerfen die Ergebnisse bestimmter Methoden.
Während es scheint wie eine gute Idee, ich glaube nicht, dass es ist. Wollen wir verunstalteten code mit Mitteilungen an die Nutzer über Ihre schlechte Praxis? Es gibt viele Produkte, die Blick auf code und Ihnen sagen, wenn Sie etwas falsch machen (oder unerwünscht), wie Flusen, Sonar und auch JavaDocs in geringerem Ausmaß.
Was ist, wenn Sie nicht einverstanden sind mit dem, was die Bibliothek Schriftsteller gesagt hat, sind wir nun erwartet, dass die Verwendung von @SuppressWarnings("return-verworfen").
Während dies kann hilfreich sein, als Lern-Hilfe, mein Punkt ist mehr zu tun mit der Trennung von Bedenken, als zu helfen, Anfänger-Programmierer. Der code (und Anmerkungen) in der Klasse sein sollte, die mit der Funktion der Klasse und nicht die Politik, Wann und wie es zu benutzen ist Methoden.