返回默认值还是引发异常?

时间:2015-04-21 09:51:47

标签: java refactoring

我对什么被认为是一种好习惯感到困惑 - 这种决策语言是否依赖?假设我有以下Java代码:

public class Stack {
    public Integer pop() {
      if (isEmpty()) return null; // or some exception maybe?
          // else get and return the top item in the stack.
      };
    }
}

pop方法的客户端需要一些Integer值,那么让客户端知道堆栈为空的最佳方法是什么?

4 个答案:

答案 0 :(得分:3)

返回null或默认值通常是一种不良做法,应首选例外。原因是当出现问题时,你应该尽可能快地失败。如果您返回null,则会在代码中的其他位置发生错误,并且您的API用户将无法找到问题所在。这称为Fail Fast

这个经验法则的一个例外是当你的API会让用户依赖流控制的异常时,所以如果你的堆栈不支持isEmpty(),那么异常并不是一个好主意。如果您的堆栈只允许peek()pop()add() - 由于某种原因,isEmpty()不允许成为API的一部分。

这两种方法的用户代码会怎样?

选项1 - 使用null

Integer x = stack.pop();
if (x != null) { 
    //do something with x
}

选项2 - 使用例外:

Integer x = null;
try { 
    x = stack.pop();
} catch (MyException e) { }
//do something with x

第二种实际上是使用异常机制进行流量控制 - 这是API设计中的一个重大缺陷。

答案 1 :(得分:2)

你可以抛出IllegalStateException

  

表示在非法或不适当的时间调用了某个方法。

在空堆栈上调用pop()是在不适当的时间进行的呼叫。

更现代的方法将返回Optional<Integer>,这是Java 8中推荐的方法{av返回null

public class Stack {
  public Optional<Integer> pop() {
    if (isEmpty()) return Option.ofNullable(null);
    return Optional.of(valueOnTheStack);
  }
}

答案 2 :(得分:0)

根据Java API,尝试从空堆栈中弹出元素应该产生异常。

因此,我认为在您的情况下,您应该这样做(假设您在Java中实现它)。其他语言可能会有不同的处理方式。

答案 3 :(得分:0)

在构建API的情况下,它应该是抽象的,并且使用Exceptions,因为它将集成在Java集成中,然后pop操作将如下所示。

public Integer pop () throws Exception
{
    if (stack.isEmpty())
        throw new java.util.EmptyStackException();

    return stack.pop();
}

如果我将其构建为Web服务,那么我将按以下方式执行此操作。基本上是为了确保通过使用堆栈的返回对象来表示不同类型的内部异常的标准化。

StackService

@WebService
class MyStack
{
    StackProvider provider;
    Stack stack;

    public MyStack (StackProvider provider)
    {
        this.provider = provider;
        this.stack = provider.readStack();
    }

    public void sync ()
    {
        provider.syncStack(stack);
    }

    public Integer pop ()
    {
        if (stack.isEmpty())
            return new StackElement(StackElement.STACK_EMPTY);

        return new StackElement(stack.pop());
    }

    public void push (Integer val)
    {
        stack.push(val);
    }
}

StackElement

class StackElement
{
    public static final char STACK_EMPTY = 0;
    public static final char ELEMENT_VALID = 1;

    public Integer value;
    public char flag;

    public StackElement (Integer val)
    {
        this.value = val;
        this.flag = StackElement.ELEMENT_VALID;
    }

    public StackElement (char flag)
    {
        this.value = null;
        this.flag = flag;
    }

    public boolean isValid ()
    {
        return (flag == 1);
    }
}

测试

class Test
{
    public static void main (String [] args)
    {
        StackProvider provider = new StackProvider("...");

        // init

        MyStackService service = new MyStackService(provide);
        MyStackServiceSoap soap = service.getMyStackServiceSoap();

        // call pop operation

        StackElement element = soap.pop();

        // checking the value

        if (element.isValid())
          System.out.println("Stack.Pop ~ " + element.value);
        else
        {
          if (element.flag == StackElement.STACK_EMPTY)
            System.out.println("Stack is Empty");
          else
            System.out.println("Unknown error");
        }

    }
}