Return 默认还是引发异常?
Return default or raise an exception?
我对什么被认为是好的做法感到困惑 - 这个决策语言是否依赖?假设我有以下 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
值,那么让客户端知道堆栈为空的最佳方法是什么?
你可以抛出 IllegalStateException
.
Signals that a method has been invoked at an illegal or inappropriate time.
在空堆栈上调用 pop()
是在不适当的时间调用。
更现代的方法将是return一个Optional<Integer>
,这是Java 8中推荐的避免[=14]的方法=] returns.
public class Stack {
public Optional<Integer> pop() {
if (isEmpty()) return Option.ofNullable(null);
return Optional.of(valueOnTheStack);
}
}
根据 Java API,尝试从空堆栈中弹出一个元素应该产生异常。
因此,我认为对于您的情况,您也应该这样做(假设您在 Java 中实现了这一点)。不过,其他语言可能会以不同的方式处理这个问题。
返回 null
或默认值 通常 是一种不好的做法,应该首选例外。原因是 当出现问题时,您应该始终努力尽快失败 。如果您改为 return 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 设计中的一大缺陷。
如果构建一个API,它应该是抽象的,并且使用异常,因为它会集成在一个Java环境中,然后弹出操作如下。
public Integer pop () throws Exception
{
if (stack.isEmpty())
throw new java.util.EmptyStackException();
return stack.pop();
}
如果我将其构建为 Web 服务,那么我将按以下方式进行。基本上是为了确保通过使用堆栈的return对象来表示不同类型的内部异常的标准化。
堆栈服务
@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);
}
}
堆栈元素
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");
}
}
}
我对什么被认为是好的做法感到困惑 - 这个决策语言是否依赖?假设我有以下 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
值,那么让客户端知道堆栈为空的最佳方法是什么?
你可以抛出 IllegalStateException
.
Signals that a method has been invoked at an illegal or inappropriate time.
在空堆栈上调用 pop()
是在不适当的时间调用。
更现代的方法将是return一个Optional<Integer>
,这是Java 8中推荐的避免[=14]的方法=] returns.
public class Stack {
public Optional<Integer> pop() {
if (isEmpty()) return Option.ofNullable(null);
return Optional.of(valueOnTheStack);
}
}
根据 Java API,尝试从空堆栈中弹出一个元素应该产生异常。
因此,我认为对于您的情况,您也应该这样做(假设您在 Java 中实现了这一点)。不过,其他语言可能会以不同的方式处理这个问题。
返回 null
或默认值 通常 是一种不好的做法,应该首选例外。原因是 当出现问题时,您应该始终努力尽快失败 。如果您改为 return 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 设计中的一大缺陷。
如果构建一个API,它应该是抽象的,并且使用异常,因为它会集成在一个Java环境中,然后弹出操作如下。
public Integer pop () throws Exception
{
if (stack.isEmpty())
throw new java.util.EmptyStackException();
return stack.pop();
}
如果我将其构建为 Web 服务,那么我将按以下方式进行。基本上是为了确保通过使用堆栈的return对象来表示不同类型的内部异常的标准化。
堆栈服务
@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);
}
}
堆栈元素
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");
}
}
}