问题
I have a helper method, hasContent(String)
, which returns true iff its argument is both non-null and contains at least one non-whitespace character. I have just enabled null analysis in Eclipse and I have found that when I use this method to execute a block of code which is conditional on the result of my helper function indicating that the string has content (and therefore cannot be null), that nonetheless Eclipse complains that my String might still be null.
The helper function
public static boolean hasContent(String text) {
if (text == null)
return false;
if (text.trim().length() == 0)
return false;
return true;
}
Example of use
...
String dataString;
try {
dataString = readStringFromFile("somefile.txt");
} catch (IOException e) {
System.err.println("Failed to read file due to error: " + e);
dataString = null;
}
// At this point dataString may be null
if (hasContent(dataString)) {
// At this point dataString must be non-null, but Eclipse warns:
// "Potential null pointer access: The variable dataString may be null at this location"
// at the following reference to dataString
System.out.println("Read string length " + dataString.length());
}
...
What is the best practice for this situation? I don't want to suppress the warning if I can avoid it. I'd prefer to tell Eclipse that if hasContent()
returns true
then it's argument is definately non-null. Is this possible? If so, how?
回答1:
The contract of your method is that if hasContent
returns true, then its argument is guaranteed to be non-null.
Eclipse cannot express or check this contract at compile time, at least without changing your code and degrading its style.
The Nullness Checker is a different tool that can express and check this contract at compile time. It does so without requiring you to change your code. You simply add the @EnsuresNonNullIf annotation your code:
@EnsuresNonNullIf(expression="#1", result=true)
public static boolean hasContent(String text) { ...
The Nullness Checker is distributed with the Checker Framework. There is an Eclipse plugin that enables you to run the Nullness Checker within Eclipse.
回答2:
It might not be the best practice, but: If an IOException is thrown, you can return false, or simply set a variable to false. If not, you can set the variable to true (in the try-block).
try {
dataString = readStringFromFile("somefile.txt");
hasContent = true;
} catch (IOException e) {
System.err.println("Failed to read file due to error: " + e);
hasContent = false;
}
回答3:
I cannot see a way to do exactly what you are attempting.
You could modify hasContent
to return the string it is passed, rather than the a boolean
and throw an Exception
if the argument is null or empty. You would then annotate the function with @NonNull
. This would however compromise your calling code in a way that I suspect you would not like since it would have to use try
/catch
logic rather than an if
.
This would make the hasContent
function:
@NonNull
public static String hasContent(String text) throws Exception {
if (text == null)
throw new Exception( "Null string" );
if (text.trim().length() == 0)
throw new Exception( "Empty string" );
return text;
}
and the calling code:
...
try {
dataString = readStringFromFile("somefile.txt");
} catch (IOException e) {
System.err.println("Failed to read file due to error: " + e);
dataString = null;
}
// At this point dataString may be null
try {
dataString = validateHasContent( dataString );
// At this point dataString must be non-null
System.out.println("Read string length " + dataString.length());
} catch( Exception e ) {
}
...
If you were prepared to make this compromise then a dedicated exception would clearly be better.
来源:https://stackoverflow.com/questions/43611344/how-can-i-annotate-my-helper-method-so-eclipse-knows-its-argument-is-non-null-if