I'm reading the source of XWalkUIClientInternal and I ran into the following code:
switch(type) {
case JAVASCRIPT_ALERT:
return onJsAlert(view, url, message, result);
case JAVASCRIPT_CONFIRM:
return onJsConfirm(view, url, message, result);
case JAVASCRIPT_PROMPT:
return onJsPrompt(view, url, message, defaultValue, result);
case JAVASCRIPT_BEFOREUNLOAD:
// Reuse onJsConfirm to show the dialog.
return onJsConfirm(view, url, message, result);
default:
break;
}
assert(false);
return false;
I've never really seen this technique nor really thought about it before, but I guess this essentially means "this is unreachable code and should not happen ever", and crash the app no matter what. Although technically you can do that with a Throwable, as long as it's not caught.
So my question is, which one is better and why, assert(false) or throwing a RuntimeException, or maybe an Error?
The biggest difference between
assert false;
(The parenthesis are not needed, assert is not a function but a statement.) and
throw new RuntimeException();
is that the assertion can be disabled. Actually, it is disabled by default unless the JVM is started with the -ea (“enable assertions”) flag. If assertions are enabled, assert false will unconditionally throw an AssertionError which derives from Error. But since assertions can be disabled, there are two problems,
the error might go undetected and
control flow analysis requires a dummy return statement after the assert (which is mostly clutter).
Therefore, in the above case, I'd certainly go with an explicit (and more concise)
throw new AssertionError("invalid type " + type);
instead of an assert followed by a dummy return.
As mentioned in the comments, this is assuming that type is an internal parameter and an invalid value indicates a bug in the logic itself. If it is an input parameter, it should be validated according to the usual rules and an IllegalArgumentException be thrown if validation fails.
Following the Oracle guidelines (Programming with assertions), assertions was designed for testing purposes:
An assertion is a statement in the Java programming language that
enables you to test your assumptions about your program. For example,
if you write a method that calculates the speed of a particle, you
might assert that the calculated speed is less than the speed of
light.
Each assertion contains a boolean expression that you believe will be
true when the assertion executes. If it is not true, the system will
throw an error. By verifying that the boolean expression is indeed
true, the assertion confirms your assumptions about the behavior of
your program, increasing your confidence that the program is free of
errors.
In your example, the developer assumed that the code never reaches the assert statement. If, by rare occurrence it does, the assert(false) will throw an Error (since it should never get there). This was done for testing purposes. So, use assert purely for testing purposes.
Related
I have an Android error handler which never returns (it logs a message and throws an error exception). If I call my error handler from a method which normally returns a value, the Android Studio lint checker reports an error because no value is returned. Is there a way either to tell Android Studio either that my error handler does not return or that the point in the code after calling it is in fact unreachable.
Of course I could put in an unnecessary return statement returning a dummy value of the correct type, but this is inelegant and clutters up my app with an unreachable statement.
I can't find a code inspection to disable to prevent the error, but even if there is one to disable, that would stop it reporting really missing return statements.
Just to repeat, this is not a Java syntax issue. People have said that a Java method must return a value of the type declared. This is
(a) not relevant
(b) not true.
The correct statement is that a Java method, if it returns, must return a value of the declared type. This bit of code
public long getUnsignedLong(String columnName)
throws NumberFormatException, NoColumnException
{
String s = getString(columnName, "getUnsignedLong");
if ((s != null) && s.matches("^[0-9]+$")) {
return Long.parseLong(s);
}
else
{
throw(new NumberFormatException("Bad number " + s));
}
}
is perfectly valid Java, and AS does not complain about it. Indeed if I insert an unnecessary return like this
public long getUnsignedLong(String columnName)
throws NumberFormatException, NoColumnException
{
String s = getString(columnName, "getUnsignedLong");
if ((s != null) && s.matches("^[0-9]+$")) {
return Long.parseLong(s);
}
else
{
throw(new NumberFormatException("Bad number " + s));
}
return 0;
}
AS complains that it is unreachable.
My problem with throwing the exception is that if it actually happens, what my app's user sees is a popup window saying that the app has stopped and asking the user if they want to disable it. This isn't very helpful to the user and isn't very helpful to me when the user reports back to me that it has happened. So instead of throwing the exception I call my fatal error handler which looks like this:-
// Always invoked with fatal = true
// Report a fatal error.
// We send a message to the log file (if logging is enabled).
// If this thread is the UI thread, we display a Toast:
// otherwise we show a notification.
// Then we throw an Error exception which will cause Android to
// terminate the thread and display a (not so helpful) message.
public MyLog(Context context, boolean fatal, String small, String big) {
new Notifier(context, small, big);
new MyLog(context, big, false);
throw(new Error());
}
Yes, I know that argument fatal isn't referenced, but its presence arranges that this particular overload of my error handler is called, and you can see that it throws an exception and doesn't return.
My actual problem is that if I replace the throw in getUnsignedLong by a call to my fatal error handler, which doesn't return, AS complains at the end of getUnsignedLong that it is returning without a value. Well, it's wrong: this point is just as unreachable as it was before. I tried putting a contract in front of MyLog saying that it always fails, but this doesn't help, and pressing right arrow at the AS error report doesn't offer any way of suppressing it. I could put in a dummy return statement or a dummy throw, but either of these would in fact be unreachable code, and I regard this as inelegant and unnecessary.
So my question stands as it was originally asked: how do I tell Android Studio that a method does not return?
Your problem seems to be a Java problem.
In Java a non-void method must return the type it should return. In your case it's the same.
So the simple solution would be to return a dummy value. It's for the sake of the compiler.
The best (harder) solution is to avoid having that kind of construction. If a method normally returns a value, the method will have a return, and in case of an error an exception can occurs. An error handler should handle an error, which means that it's not the default behavior.
Also, you may want to have a look here: unreachable-code-error-vs-dead-code-warning-in-java
If you worry about unit test coverage. When you do unit test, there is always some parts of the code that you can't reach. That's one of the reason why we almost never want a coverage of 100
A method is basically code that you want to access in different ways (easier to call one method in a line than code >50 lines, etc.). When you create the method you either call it:
"void" (never returns an value),
"String" (returns a set of characters/letters),
"int" (returns a number within it's bounds. Integer Types),
"boolean" (returns a 2-type value, true or false).
And more...
In those methods you cand do whatever you want, but make sure that in the end they return the value type specified in the initialization.
Example:
int y = 2;
boolean booleanMethod(){
y = 6;
return true; //or false, doesn't really matter in this case.
}
boolean trueOrFalse(){
if (y == 2) return true;
else return false;
}
//or
void method(int nr){
nr = 10;
}
Those are just some basic examples of methods in Java*, because your problem was a syntax one, not really an AS one.
AS complains that it is unreachable.
Android Studio is correct. Android Studio is correctly implementing the reachability rules in the Java Language Specification.
This is a Java semantics issue. (It is not a syntax issue, but lets not split hairs.)
Lets create a simple but complete example to illustrate why Android Studio is correct:
public class Test {
public int method1() throws Exception {
int result;
method2();
return result;
}
public boolean method2() throws Exception {
throw new Exception("bad stuff");
}
}
$ javac Test.java
Test.java:5: error: variable result might not have been initialized
return result;
^
1 error
(I don't have a copy of Android Studio to hand, but that would give a similar compilation error to javac. Try it.)
Why is this an error? After all, by your reasoning, the return statement should be unreachable.
Here's the problem. That is NOT what the JLS says. In fact, JLS 14.21 says the following, among other things. (These statements are excerpts, and I have added the numbers for clarity. "iff" is an abbreviation that the JLS uses for "if and only if".)
"The block that is the body of a constructor, method, instance initializer, or static initializer is reachable."
"The first statement in a non-empty block that is not a switch block is reachable iff the block is reachable."
"A local variable declaration statement can complete normally iff it is reachable."
"Every other statement S in a non-empty block that is not a switch block is reachable iff the statement preceding S can complete normally."
"An expression statement can complete normally iff it is reachable."
Consider the body of method1.
By #1 - the block is reachable
By #2 - the declaration of result is reachable.
By #3 - the declaration can complete normally
By #4 - the call to method2() is reachable
By #5 - the call can return normally
By #4 - the return statement is reachable.
But it is also clear that if we reached the return statement, then result will not have been definitely initialized. (This is obviously true. And JLS 16 bears this out.)
OK so why did they specify Java this way?
In the general case, method1 and method2 can be in separate compilation units; e.g. cases A and B. That means that the methods can be compiled at different times, and only brought together at runtime. Now, if the compiler needs to analyze the body of B.method2 to determine if the return in A.method1 is reachable, then consider what happens if:
the code for B.method2 is modified and B recompiled after compiling A, or
a subclass C of B is loaded in which C.method2 returns normally.
In short, if we need to take account of the flow within of method2 when analyzing reachability in method, we cannot come to a come to a answer at compile time.
Conclusions:
The JLS clearly says / means that the (my) example program is erroneous.
It is not a specification mistake.
If Android Studio (or javac) didn't call the example erroneous, then it wouldn't be a valid implementation of Java.
I want to know the the best programming practice in the following use-case for a method say myMethod--
1) myMethod has some numerical purpose - say modify the contents of an array which is a private variable of the class
2) Before it does so, i need to run some critical checks on the numbers,say check1, check2, check3, any of which if fail, there is no point in going ahead. for eg. check might be to check for any negative numbers in array.
So this brings the question, what should myMethod return, how should the calling function be told that checkX has failed.
You should throw Exceptions if any of these checks fail.
Now the question is what kind of Exception to throw. Checked or unchecked? Checked Exceptions must be caught by the calling code where as unchecked do not (but that means they might bubble up to the top of the call stack all the way up to your main method). There is vigorous debate which is better. Either way, make sure to document which Exceptions are thrown.
In general, you should use checked exceptions for recoverable conditions and unchecked exceptions for programming errors (Effective Java 2nd ed Item 58)
there are many built in unchecked Exceptions in Java that you should use in preference to writing your own including but not limited to.
IllegalArgumentException
IllegalStateException
IndexOutOfBoundsException
NullPointerException
Take a look at the core Java methods to see what they throw.
Exceptions are better than return values because:
You must rely on users to check the return value and do something about it.
You are stuck with a method signature that returns a boolean or return code which might not be what you want.
The Exception can have a very descriptive error message explaining why it was thrown.
You can create a custom checked exception as follows:
class ArrayModificationException extends Exception{
public ArrayModificationException(String message){
super(message);
}
}
now in your "myMethod" add following:
void myMethod() throws ArrayModificationException{
//code to check conditions before modifications
//code to modify an array
if(check fails){
throw new ArrayModificationException("cusom message");
}
}
where custom message would be specific message conveying the exact reason of failure.
Of course the called will decide if to handle it or re-throw it. If this is one of conditions where your code should not try to recover itself you can design this as run-time exception and just throw it without throws clause for your method
There is no "best practice" here. It depends entirely on what your code does, where it's being executed, what the caller of the method expects, what should happen in erroneous cases, etc. Context is key here.
One possibility would be to throw an exception from the failing check, which would then be caught in the calling method.
Another option would to have myMethod return a boolean of true if all of the checks pass and the modification/calculation is done, and false otherwise.
As new_web_programmer said, though, it completely depends on what you are trying to do.
In general after a failed validation I do
throw new IllegalArgumentException("... Clue to the error and its repair...");
IllegalStateException is an alternative here.
This enables the function to continue as desired on success.
If the exception must be catched, not propagated, use your own Exception.
If the check failure is expected to be an exceptional circumstance, then throw an exception. Good examples are if a parameter is null but null is disallowed, or if a array index is out of range.
If your functio is supposed to return a reasonable value based on the inputs, such as returning the Point clisest to 0,0 then you could return a reasonable value based upo the check failures. For example, retur null if the array of Points is empty, or if the array itself is null.
In any case, be sure to clearly document (in the method's javadoc) what inputs result in the failure and what the expected behavior is, so that your callers are not surprised.
This brings up a very old debate whether to use exceptions or error codes.
You can read more about it here:
Exceptions or error codes
try{
check1
}catch(Exception e){
throw new CustomException("failed due to check1");
}
Some thing like this may be a better practice.
I use assertions in Java in a standard way, having them turned on in my IDE. So they are not part of production release. Lately I have been seeing code examples with throw new AssertionError() and I started thinking about the situation where AssertionError should be used instead of assertion.
My guess is that main difference is the optionality of asserts so they don't slow down the production performance and so they can occur quite often in the code, but fixing hardly reproducible bugs reported from users is harder.
For AssertionError, the exact opposite applies.
I also find AssertionError more practical in places in code where the execution should not get, instead of using assert false //We should not be here. Especially if the return value is required. For example:
int getFoo(AnEnum a){
if (a == AnEnum.ONE)
return bar();
else if (a == AnEnum.TWO)
return SOME_VALUE;
//else
assert false; //throw new AssertionError();
return -1; //not necessary when usin AssertionError
}
Is my reasoning correct?
What are the other differences/use cases/best practices/limitations
of either approach?
In regards to providing a description in the AssertionError - Should it be provided or is the mere fact that it is an Error (and
of assertion type) enough to be more or less sure that stack trace
will be provided in case of found bugs?
In the technote "Programming With Assertions: Control Flow Invariants" the following code is given:
void foo() {
for (...) {
if (...)
return;
}
assert false; // Execution should never reach this point!
}
But the following note is given as well:
Note: Use this technique with discretion. If a statement is unreachable as defined in the Java Language Specification, you will get a compile time error if you try to assert that it is not reached. Again, an acceptable alternative is simply to throw an AssertionError.
You may not expect an AssertionError to be thrown when assertions are turned off. As AssertionError constructors are public, and since there is likely no substitution for AssertionError(String message, Throwable cause), I guess that you should expect them even if they are turned off.
Throwing an AssertionError on unreachable code (i.e. without any real expression to be evaluated) will never slow down the code, as Jon Skeet suggested, so it won't hurt with regards to performance.
So in the end throwing the AssertionError seems OK.
I would advise against throwing AssertionErrors directly. If you choose to rely on AssertionErrors for checking invariants, pre/post conditions, state conditions, etc. you're still better off using regular assertions with the "-ea" flag turned on in production as well.
The reason is that the assertions mechanism (other than being optimized at the compiler level) gives you a chance to turn on or off all assertions at once. Even if you can't think of a reason to do that now, if you come across a reason in the future, just consider that you'll have to go over all your throw new AssertionError(...) type code and surround it with a nasty if clause. You get the picture.
Just as you wouldn't want a magic number hard coded into many places in your code, and would probably use a constant instead, you shouldn't infect your code with many duplications (i.e. the throw new AssertionError(...) part).
Another word about assertions though. I believe that you should think twice before relying on assertion errors in production code. The reason is that an AssertionError is very generic. It has a message and a cause, but that's pretty much it.
Consider instead using specific RuntimeException subclasses that will convey more information both by being of a specific class more related to the problem, as well as by carrying actual data related to the problem.
As a simple example, consider a case you mentioned in your question where there's some part of the code that you don't expect to reach. An assertion or an AssertionError would convey the fact that you reached some unexpected code, but not much more. Using a specific RuntimeException could also deliver the state of the local variables and parameters of the method at that point in time. You could argue that this is doable with setting the message of the assertion or AssertionError to contain this information, but this does not work when using automatic error logging/handling mechanisms. Such mechanisms can handle unexpected behaviors using the visitor pattern on the different sub classes of RuntimeException you're using to check unexpected behavior (by handle I also mean fail-fast, not necessarily recovery).
I have never understood what is assert used for, even though I have read plenty examples, they don't really let me know what or why should I use it for.
So Instead of asking an example, I'm gonna provide one and let me know if this is the proper usage of assert.
// The idea is that the `mode` variable should be 0 or 1, and no other number.
switch(mode) {
case 0:
// do stuff
break;
case 1:
// do other stuff
break;
default:
// assert code?
}
If this is correct, please let me know how to use it in this case. If this is not how it is supposed to use, please provide an example.
Not in this case.
If you're asserting a value, you're making a statement that, before some critical evaluation is done using this value, that it is what you assert it to be. You can assert that the value isn't null, or that it's less than 2, or something before you reach your critical code block.
assert (mode >= 0 && mode < 2); // Ensures that `mode` is between 0 and 1.
// Switch statement to follow
I would not encourage the use of that here. Your code would not read well, and unless you enable assertions with the -ea flag, your assertion would not work.
Instead, what you can do is throw an exception of some kind - if it's not 0 or 1, then the mode is an illegal value which cannot be processed, leading to exceptional/undefined behavior. Throw an exception of some kind.
switch(mode) {
case 0:
// do stuff
break;
case 1:
// do other stuff
break;
default:
throw new IllegalArgumentException("Mode is illegal");
}
assert object != null;
object.doSomething();
assert is used to verify the correctness of some precondition, invariant, or postcondition. In the example, we want to make sure object is not null when some method is called on it.
One thing to remember is that assert should never be executed in production code. We only make use of it when testing. There is a Java option to turn it on or off.
As for your specific example, you could use:
assert mode == 0;
assert mode == 1;
at the very beginning of the switch block to make sure only 0 and 1 are passed in.
P.S. The discussion on when to use assertion vs exception might help your understanding. The idea is that
Exceptions address the robustness of your application while assertions
address the correctness of your application.
Assertions are basically used to check something that should never happen.
Some assertions use cases from http://www.javapractices.com/topic/TopicAction.do?Id=102
pre-conditions (in private methods only) - the requirements which a method requires its caller to fulfill.
post-conditions - verify the promises made by a method to its caller
class invariants - validate object state
unreachable-at-runtime code - parts of your program which you expect to be unreachable, but which cannot be verified as such at compile-time (often else clauses and default cases in switch statements)
So the usage of assertion in your code is not correct
public Card getCard()throws IOException{
Card c = null;
String cardInfo = null;
assert readStream != null: cardInfo = readStream.readLine();
assert cardInfo != null: c = CreateCard(cardInfo);
return c;
}
I'm a little outta practice and I am trying to improve my code quality by using the assert statement to test for nulls. The way it seems to work I end up having to daisy chain my assertions because if the first thing I test for is null, then the next one is gonna be a null as well....
Here are some guidelines with regards to assertions
Don't use assertions to validate parameters of public functions.
These functions should throw NullPointerException,
IllegalArgumentException, and other relevant exceptions instead.
Since public functions will be used by other programmers, you should
make sure that they get the right errors if they mess up.
Use assertions to check preconditions and postconditions on
parameters of protected and private access methods.
Don't use assertions to check for software user errors. If you expect
the user of your web-based online sales system to enter a 10-digit
credit card number and she enters only 9 digits, don't use an assert.
Instead, throw IllegalArgumentException. If you use assert, as soon
as someone turns off assertions on your servlet container, the
checking logic in your system would go away.
Use assertions to check parameters and variables for conditions that
shouldn't happen
Use assertions to check for invalid code branches
Don't use an assertion to do any work. Assertions are developer-level
errors and shouldn't be used to repair state in the program or
perform complex logging. Also, don't forget that if a user runs the
program without assertions, the code will be gone. If that code was
critical to the functioning of the program, you could be in deep
trouble.
Don't bother internationalizing assertion error messages. Again,
since assertions are developer-level issues, internationalizing them
would be a waste of time.
Use assertions to check post conditions. If you create a method and
expect that it will never to return null to the user
The value of an assertion is that it can be ON in development and OFF in production. While on, it reveals bugs, presumably before they do much damage, prior to a release. While off, the assertions are inactive and (hopefully) sport a negligible performance impact.
I think the question to ask yourself is: "Self, does my usage of assertions meet those criteria?"