The @Contract annotation is used for defining a contract that a method must meet. This lets the IDE find problems in methods which call methods that you have annotated. You can use this annotation not only for annotating your own code but also for other existing libraries.
The @Contract annotation has two attributes — value and pure. The value attribute contains clauses describing causal relationship between arguments and the returned value.
The pure attribute is intended for methods that do not change the state of their objects, but just return a new value. If its return value is not used, removing its invocation will not affect program state or change the semantics, unless the method call throws an exception (exception is not considered to be a side effect).
A method should not be marked as pure if it does not produce a side effect by itself, but it could be used to establish the happens-before relation between an event in another thread, so that changes performed in another thread might become visible in current thread after invocation of this method. On the other hand, some synchronized methods could be marked as pure, because the purpose of synchronization here is to keep the collection internal integrity rather than to wait for an event in another thread. "Invisible" side effects (such as logging) that do not affect important program semantics are allowed.
A contract is a set of clauses that describe an input and an output. They are separated with the -> symbol: "A -> B". This forms a contract meaning that when you provide A to a method, you will always get B. Clauses in a contract must be separated with the ; (semicolon) symbol. For example:
@Contract("_, null -> null")
The method returns null if its second argument is null.
@Contract("_, null -> null; _, !null -> !null")
The method returns null if its second argument is null, and not-null otherwise.
@Contract("true -> fail")
A typical assertFalse() method which throws an exception if true is passed to it.
@Contract("_ -> this")
The method always returns its qualifier (e.g. StringBuilder.append).
@Contract("null -> fail; _ -> param1")
The method throws an exception if the first argument is null, otherwise it returns the first argument (e.g. Objects.requireNonNull).
The method throws an exception if arguments meet argument constraints
new
Every time the method is executed, it returns a non-null new object that is distinct from other objects existing in the heap prior to method execution. If the method is pure, the new object is not stored in any field or array and will be lost if method return value is not used.
this
The method returns non-null this reference
param1 (param2, param3, etc.)
The method returns its first (second, third, etc.) argument
As we’re closing in on the release date, we’re going to publish more details on the new features of IntelliJ IDEA 13. Today we’d like to tell you about the new @Contract annotation.
If you are aware of @Nullable/@NotNull annotations, you probably know how helpful they are against NullPointerException. The new @Contract annotation brings one more layer of safety for your code by defining dependencies between method arguments and return values. This information lets IntelliJ IDEA provide smarter control flow analysis for your code and avoid probable errors.
Here’s an example: say we’ve got a method sort() that returns a sorted list or a null value if the argument is null.
Now if we try to to call this method with a null value and check the result against null, IntelliJ IDEA will not complain because it doesn’t know that a null input yields a null output.
How can we help IntelliJ IDEA? That’s right… Decorate the sort() method with a @Contractannotation, specifying that null inputs yield null outputs:
Now IntelliJ IDEA can see that the sort() method always returns null and the if statement is redundant. The corresponding message appears in the editor.
The @Contract annotation value has the following syntax:
fail – the method throws exception, if the arguments satisfy argument constraints
The @Contract annotation is a powerful and flexible tool that helps make your APIs safer. However, you can use it not only for annotating your own code but also for other existing libraries.
Once you’ve configured the annotations for the project libraries, the IDE stores this information in simple XML files so it can be shared with the team via version control.
To enable the annotations in your project, just add <IntelliJ IDEA Home>/lib/annotations.jar to the classpath via Project Structure.
UPDATE: Please find the latest annotations.jar in Maven repository.
We sacrifice the art of writing good and performant code for the short term gains of improving developer productivity.
Annotations can be powerful but only when used to add context and information to the code. But trying to configure your application with them is nothing less that a crime.