Reputation: 6197
public WHATTOWRITEHERE test()
{
try
{
transaction.begin();
code which may trigger exception
transaction.commit();
return true;
}
catch (javax.script.ScriptException ex)
{
transaction.rollback();
return ex.getMessage();
}
}
the code above intend to do something, if its OK then return true
if not (error happened), this error message string
should be returned. It do possible with Php but not with Java
EDIT: expection cant go outside, it has to be handled right here.
Upvotes: 0
Views: 3791
Reputation: 1731
If you are using Java 8 you could return an Optional<String>
. Then if the code succeeds you return an empty Optional and if there is a failure you return an optional wrapping the failure message.
Upvotes: 0
Reputation: 77454
In your case, exceptions should probably be used, not hidden. It's not a result but an error. Learn how to do exception handling in transactions!
Functional programming fanboys will advocate a Monad-like structure, as you can find in the Optional<T>
API of Java 8.
I.e. you could return Optional<String>
and leave it unset on success (if you do not have a return false
and a return true
).
For clarity it would be better to build something like this instead with custom classes:
interface Result {}
class BooleanResult implements Result {
boolean result;
public boolean getResult() { return result; }
}
class ErrorResult implements Result {
Exception cause;
public Exception getCause() { return cause; }
}
You could emulate Optional
with null
values (if you have only one boolean result). On success, return null
. Non-null values indicate errors.
String perform() {
try{
...
return null; // No error
} except(Exception e) { // bad code style
return e.getMessage(); // Pray this is never null
}
}
String err = perform();
if (err != null) { throw up; }
Similar APIs are fairly common in old C libraries. Any return value except 0 is an error code. On success, the results are written to a pointer provided at the method call.
You could use Object
.
public Object perform() {...}
Object o = perform();
if (o instanceof Boolean) { ...
This is 1980s programming style. This is what PHP does, so it actually is possible in Java! It's just bad because it is no lpnger type safe. This is the worst choice.
I suugest your try 1., 3., 2., 4., 5. in this preference. Or better, only consider the options 1 and 3 at all.
As for option 1. you really should learn how to use try-with-resources. Your transaction is a resource.
When done right, your code will look like this:
try(Transaction a = connection.newTransaction()) {
doSomethingThatMayFail(a);
a.commit();
} // No except here, let try handle this properly
Java will call a.close()
even if an exception occurs. Then it will throw the exception upwards. Sour transaction class should have code like this to take care of the rollback:
public void close() {
if (!committed) rollback();
}
This is the most elegant and shortest and safe-to-use approach, as Java ensures close()
is called. Throw the Exception, then properly handle it. The code snipped you showed above is an anti-pattern, and known to be very error prone.
Upvotes: 1
Reputation: 40335
You can't return multiple types but you can redesign so you don't have to. Some possibilities:
I recommend option 1. You're already handling an exception, you can see its use for it error handling. No reason to stop it in its tracks there, handle any local cleanup then keep it going up to the caller.
Some hastily constructed examples now that I'm back at a keyboard, intended only to illustrate concepts, not to be exhaustive or necessarily used verbatim:
Cleanup then rethrow:
public boolean test () throws javax.script.ScriptException {
try {
transaction.begin();
...
transaction.commit();
return true;
} catch (javax.script.ScriptException ex) {
transaction.rollback();
throw ex;
}
}
Clean up then rethrow a different exception type if needed:
public boolean test () throws MyGreatException {
try {
transaction.begin();
...
transaction.commit();
return true;
} catch (javax.script.ScriptException ex) {
transaction.rollback();
throw new MyGreatException(ex);
}
}
Return an object that provides status information (this is just a quick example of the general idea):
public class TransactionResult {
private final boolean failed;
private final String reason;
/** Construct a result that represents a successful transaction. */
public TransactionResult () {
failed = false;
reason = null;
}
/** Construct a result that represents a failed transaction with a reason. */
public TransactionResult (String failedReason) {
failed = true;
reason = failedReason;
}
public boolean isFailed () {
return failed;
}
public String getReason () {
return reason;
}
}
And then:
public TransactionResult test () {
TransactionResult result;
try {
transaction.begin();
...
transaction.commit();
result = new TransactionResult();
} catch (javax.script.ScriptException ex) {
transaction.rollback();
result = new TransactionResult(ex.getMessage());
}
return result;
}
Etc.
Upvotes: 7
Reputation: 8587
Exceptions can't go outside, it has to be handled here.
I must say this restriction can only make the interface more difficult to use. Assume you want to return something for the caller to check whether an exception happened in this method, while the caller can ignore the returned value no matter what. So I guess you want to give the caller some flexibility: that he/she doesn't need to bother with the final result if possible. But with the exception approach the caller can still do that, with empty (not recommended) catch clauses.
Exception is the best approach here. Unless "outside" is an environment where exceptions are not supported. Then you have no choice but to come up with something like Try
in Scala.
Upvotes: 1
Reputation: 21
UGLY Workaround but if you really want to do this you can always define a Helper class which wraps status and Error Message, but I would prefer @JsonC's approach.
// Helper class
class Pair<First,Second>{
private First first;
private Second second;
Pair(First first,Second second){
this.first = first;
this.second = second;
}
public First getFirst(){ return this.first; }
public First getSecond(){ return this.second; }
}
// Function returning two types
public Pair<boolean,String> returnSomething(){
try {
return new Pair<boolean,String>(true,null);
}catch(Exception e){
return new Pair<boolean,String>(false,e.getMessage());
}
}
// Calling this method would look like this
Pair<String,boolean> result = returnSomething();
// Retrieve status
boolean status = result.getFirst();
// Retrieve error message (This is null if an exception was caught!)
String errorMessage = result.getSecond();
Upvotes: 2
Reputation: 86252
If you insist, you can return Object
. In that case, true will be autoboxed to Boolean.TRUE
. It’s certainly not recommended, and it will give the caller some extra trouble figuring out whether the returned object is a String
or a Boolean
. To make matters worse, the caller has no guarantee that return types are limited to the mentioned two, but should also take into account that it could be yet another class.
Better options depend on the situation, so I probably cannot tell you what’s best. A couple of ideas spring to mind, but please don’t use uncritically: (1) Return String
, and return null
instead of true on success. (2) Design your own return class; for instance, it may hold both a boolean and a message string.
Upvotes: 2
Reputation: 137398
Don't return anything. Just re-throw the original exception after you roll-back.
public void test()
{
try
{
transaction.begin();
code which may trigger exception
transaction.commit();
}
catch (javax.script.ScriptException ex)
{
transaction.rollback();
throw ex; // re-throw the original exception
}
}
Upvotes: 3