【问题标题】:Correct way of returning an error code in a method在方法中返回错误代码的正确方法
【发布时间】:2016-08-02 06:01:40
【问题描述】:

我在“Point”类中有这个方法:

public Point sumPoints(Point p) {
        if(dimension != p.getDimension())
            throw new RuntimeException("Wrong dimensions.");

        Double[] coord = new Double[dimension];
        for(int i = 0; i < dimension; i++)
            coord[i] = coordinates[i] + p.getCoord(i);
        Point P = new Point(coord);

        return P;

这个想法是点可以是 n 维的,所以我应该在尝试将它们相加之前检查点的尺寸是否匹配。问题是在它们不匹配的情况下,我不能返回一个特定的值(例如-1,就像我在C 中所做的那样),因为返回类型是Point

在这些情况下我应该怎么做? RuntimeExeption 是一种好的做法吗?

【问题讨论】:

  • 抛出异常没问题,但IllegalArgumentExceptionRuntimeException的子类型)更有意义。
  • 这完全取决于你的口味。抛出异常是昂贵的,但如果在正确的时刻使用它们也不会气馁。我认为你可以把它扔在这里。但你也可以只返回 null 并使用该值做一些事情。

标签: java


【解决方案1】:

出于多种原因,异常处理是在 Java 中实现错误处理的一种更为优雅的方式。

错误代码

返回错误代码works well in C 尤其是因为能够在 C 中将指针作为函数参数传递:通过这种方式,您可以例如在函数内部创建一个新对象,并通过传递给函数的指针“返回”它,并让函数实际上 return 一个正确的错误代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int create_message_str(char *p_message, const size_t p_message_len)
{
    int result = -1;

    const char message[] = "Hello, world!";
    if (NULL != p_message && strlen(message) <= p_message_len)
    {
        strcpy(p_message, message);
        result = 0;     
    }

    return result;
}

int main(int argc, char **argv)
{
    int result = EXIT_FAILURE;

    const size_t p_message_len = 13;
    char *p_message = malloc(p_message_len * sizeof(char));

    if (create_message_str(p_message, p_message_len) == 0)
    {
        printf("%s\n", p_message);
        result = EXIT_SUCCESS;
    } 
    else
    {
        fprintf(stderr, "%s\n", "Could not copy string to pointer memory.");
    }

    free(p_message);

    return result;
}

然而,在 Java 中,您必须创建一个实例,例如某种可变的Supplier-like 对象,用于保存对对象的引用,该对象将由 C 函数中的指针引用:

public class ReferenceSwapper {

    private static class MutableSupplier<T> implements Supplier<T> {

        private T supplied;

        public MutableSupplier(final T supplied) {
            this.supplied = supplied;
        }

        @Override
        public T get() {
            return supplied;
        }

        public void set(final T supplied) {
            this.supplied = supplied;
        }

    }

    public static void main(final String[] args) {
        final MutableSupplier<String> firstSupplier = new MutableSupplier<String>("foo");
        final MutableSupplier<String> secondSupplier = new MutableSupplier<String>("bar");
        System.out.println("Before reference swap: " + firstSupplier.get() + secondSupplier.get());
        swapSupplied(firstSupplier, secondSupplier);
        System.out.println("After reference swap: " + firstSupplier.get() + secondSupplier.get());
    }

    private static <T> void swapSupplied(final MutableSupplier<T> firstSupplier,
            final MutableSupplier<T> secondSupplier) {
        final T firstSupplied = firstSupplier.get();
        final T secondSupplied = secondSupplier.get();
        firstSupplier.set(secondSupplied);
        secondSupplier.set(firstSupplied);
    }
}

这段代码打印出来:

Before reference swap: foobar
After reference swap: barfoo

如您所见,由于 pass-by-value semantics,这在 Java 中非常复杂。

例外情况

不过,Java 提供了一种更高级别的方式来定义错误处理行为:异常。尽管some people debate if the idea of exceptions are a good thing or notexception handling is really just fancy conditional logic,它们是Java 语言的一部分,can work well 用于报告异常(即错误)状态。

作为Andy Turner already mentioned,抛出IllegalArgumentException 将是报告与方法的特定参数有关的错误的最自然方式,您不应该(通常)必须捕获和处理:您会假设人们使用sumPoints(Point p) 足够聪明,可以传递正确的参数,或者如果不是这样,至少会导致程序停止。但是,如果您确实认为这是一个常见的事件,那么至少是通过明智的编程无法避免的事件(例如,如果数据是从磁盘读取的并且可能以某种方式损坏或不可用),那么最好抛出一个捕获的异常以强制调用方法处理发生这种情况的情况。

【讨论】:

    【解决方案2】:

    Java 中的异常之处在于,您可以编写自己的从 Exception 扩展而来的类,以便在处理所有可能遇到程序的异常的类中使用它,然后您只需抛出它。 示例:

    public class Erreur extends Exception{
    String message; 
    public Erreur(String message){
    this.message=message;    
    }    
    public String getMessage(){ return message;}
    }
    

    然后

    public class Calcule {
        public static double division(double x, double y) throws Erreur{
        double r=0;
        Erreur erre=new Erreur("can't divide by zero");
        if(y==0) throw (erre); 
        else r=(x/y);
        return r;
                 } 
       }
    

    【讨论】:

    • 虽然在某些情况下,让程序特定的所有异常类型都从一个公共类继承是有用的,但这样做只是为了便于捕获它们是对异常处理机制的滥用: Erreur 可以代表截然不同的问题,因此尝试使用您的代码的人将花费大量时间来弄清楚如何处理每个案例。
    • 完全同意,我写的只是以防有人试图处理一些特殊的例外情况。
    【解决方案3】:

    简而言之,您的问题的答案是肯定的。异常是处理错误的公认方式。虽然有很多从RuntimeException 继承的更具体的异常。我想到了IllegalArgumentException。您也可以编写自己的继承自RuntimeException 的异常。然后当然有一个关于使用未检查(继承自RuntimeException)或检查(继承自Exception)的异常的激烈讨论。只需在 Google 中输入“runtimeexception vs exception”,您就会得到一个全屏链接,让您保持忙碌:)。这里只是一个例子:difference between java.lang.RuntimeException and java.lang.Exception。对此没有明确的答案。您必须自己选择。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-04
      • 2017-02-20
      • 2015-03-21
      • 2018-03-23
      • 1970-01-01
      • 2012-08-07
      • 1970-01-01
      • 2019-01-04
      相关资源
      最近更新 更多