Java,如果我想从函数中返回不同的类型怎么办?

时间:2016-08-27 14:14:28

标签: java

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();
    }
}

上面的代码打算执行某些操作,如果可以,则返回true如果没有(发生错误),则应返回此错误消息string。它可以用Php但不能用Java

编辑:考试不能到外面,必须在这里处理。

7 个答案:

答案 0 :(得分:7)

您无法返回多种类型,但您可以重新设计,因此您不必这样做。一些可能性:

  1. 不要返回错误消息。改为抛出或重新抛出异常,让调用者处理它。
  2. 创建一个可以封装成功和错误状态以及所有相关信息的类,返回该实例。
  3. 我建议选项1.您已经处理了异常,您可以看到它用于错误处理。没有理由在那里停止它,处理任何局部清理然后让它继续调用。

    现在有些匆匆构建了一些例子,我回到键盘上,只是为了说明概念,不是详尽无遗或者必须逐字使用:

    清理然后重新抛出:

    public boolean test () throws javax.script.ScriptException {
        try {
            transaction.begin();
            ...
            transaction.commit();
            return true;
        } catch (javax.script.ScriptException ex) {
            transaction.rollback();
            throw ex;
        }
    }
    

    如果需要,清理然后重新抛出不同的异常类型:

    public boolean test () throws MyGreatException {
        try {
            transaction.begin();
            ...
            transaction.commit();
            return true;
        } catch (javax.script.ScriptException ex) {
            transaction.rollback();
            throw new MyGreatException(ex);
        }
    }
    

    返回一个提供状态信息的对象(这只是一般概念的一个简单示例):

    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;
        }
    
    }
    

    然后:

    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;
    }
    

答案 1 :(得分:3)

不要退货。回滚后只需re-throw the original exception

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
    }
}

答案 2 :(得分:2)

如果你坚持,你可以返回Object。在这种情况下,true将被自动装箱到Boolean.TRUE。这当然不推荐,它会给调用者一些额外的麻烦,弄清楚返回的对象是String还是Boolean。更糟糕的是,调用者无法保证返回类型仅限于上述两种类型,但也应考虑到它可能是另一类。

更好的选择取决于具体情况,所以我可能无法告诉你什么是最好的。我想到了一些想法,但请不要不加批判地使用:(1)返回String,并在成功时返回null而不是true。 (2)设计自己的归级课程;例如,它可以同时包含布尔值和消息字符串。

答案 3 :(得分:2)

UGLY解决方法但是如果你真的想要这样做,你总是可以定义一个包装状态和错误消息的Helper类,但我更喜欢@JsonC的方法。

// 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();

答案 4 :(得分:1)

  

例外不能出去,必须在这里处理。

我必须说这种限制只会使界面更难以使用。假设您要为调用者返回一些内容,以检查此方法中是否发生异常,而调用者无论如何都可以忽略返回的值。所以我想你想给调用者一些灵活性:如果可能的话,他/她不需要为最终结果而烦恼。但是使用异常方法,调用者仍然可以使用空(不推荐)catch子句。

例外是这里最好的方法。除非“外部”是不支持异常的环境。那么你别无选择,只能在Scala中提出类似Try的内容。

答案 5 :(得分:1)

  1. 在您的情况下, 例外应该使用,而不是隐藏。这不是结果,而是一个错误。了解如何在事务中进行异常处理!

  2. 函数式编程粉丝将提倡类似Monad的结构,您可以在Java 8的Optional<T> API中找到。

    即。您可以返回Optional<String>并在成功时将其取消(如果您没有return falsereturn true)。

  3. 为了清楚起见,最好使用自定义类来构建类似的东西:

    interface Result {}
    class BooleanResult implements Result {
      boolean result;
      public boolean getResult() { return result; }
    }
    class ErrorResult implements Result {
      Exception cause;
      public Exception getCause() { return cause; }
    }
    
  4. 您可以使用Optional值模拟null(如果只有一个布尔结果)。成功后,返回null。非空值表示错误。

    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; }
    

    类似的API在旧C库中相当常见。除0之外的任何返回值都是错误代码。成功时,结果将写入方法调用中提供的指针。

  5. 您可以使用Object

    public Object perform() {...}
    
    Object o = perform();
    if (o instanceof Boolean) { ...
    

    这是20世纪80年代的编程风格。 这就是PHP所做的,所以它实际上 可能在Java中!它只是,因为它不是lpnger类型的安全。这是最糟糕的选择。

  6. 我在这个偏好中假设您尝试1.,3.,2.,4.,5。或者更好,只考虑选项1和3。

    对于选项1.你真的应该学习如何使用try-with-resources。您的交易 是一种资源。

    完成后,您的代码将如下所示:

    try(Transaction a = connection.newTransaction()) {
      doSomethingThatMayFail(a);
      a.commit();
    } // No except here, let try handle this properly
    

    如果发生异常,Java将调用a.close() 甚至。然后它将向上抛出异常。酸性事务类应该有这样的代码来处理回滚:

    public void close() {
      if (!committed) rollback();
    }
    

    这是最优雅的最短的安全使用方法,因为Java确保调用close()抛出异常,然后正确处理它。你在上面展示的代码是一个反模式,并且已知非常容易出错。

答案 6 :(得分:0)

如果您使用的是Java 8,则可以返回Optional<String>。然后,如果代码成功,则返回一个空的Optional,如果出现故障,则返回一个可选的包装失败消息。