有一个返回语句只是为了满足语法不好的做法?

考虑下面的代码:

public Object getClone(Cloneable a) throws TotallyFooException { if (a == null) { throw new TotallyFooException(); } else { try { return a.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } //cant be reached, in for syntax return null; } 

return null; 是必要的,因为一个exception可能被捕获,但是在这种情况下,因为我们已经检查过它是否为空(假设我们知道我们调用的类支持克隆),所以我们知道try语句永远不会失败。

为了满足语法和避免编译错误(有一个解释它不会被达成的注释),还是有更好的方法来编写类似这样的代码是不好的做法,返回语句是不必要的?

没有额外的返回声明的更清晰的方式如下。 我也不会捕获CloneNotSupportedException ,但让它去调用者。

 if (a != null) { try { return a.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } throw new TotallyFooException(); 

几乎总是有可能摆脱这个命令,最终得到比你最初的语法更直接的语法。

这绝对是可以达成的。 请注意,您只是在catch子句中打印堆栈跟踪。

a != null的情况下, 将会有一个exception,将return null 。 你可以删除这个语句,并用throw new TotallyFooException();replace它throw new TotallyFooException();

一般情况下* ,如果null是一个方法的有效结果(即用户期望它,它意味着什么),那么返回它作为“未find数据”或发生exception的信号不是一个好主意。 否则,我看不出有什么问题,为什么你不应该返回null

Scanner#ioException方法为例:

返回此Scanner底层Readable所抛出的IOException如果不存在这样的exception,则此方法返回 null

在这种情况下,返回值null具有明确的含义,当我使用方法时,我可以肯定,我只有null因为没有这样的exception,而不是因为方法试图做一些事情,失败。

*请注意,即使意义不明确,有时您也希望返回null 。 例如HashMap#get

null的返回值不一定表示映射不包含该键的映射; 地图也可能明确地将密钥映射到 空值containsKey操作可以用来区分这两种情况。

在这种情况下, null可以表示find并返回null ,或者hashmap不包含请求的键。

为了满足语法和避免编译错误,在最后join额外的返回语句是不好的做法(注释解释不了)

我认为return null是一个不可达分支的总站不好的做法。 抛出一个RuntimeExceptionAssertionError也是可以接受的)是更好的办法,因为到了那一行,出现了一些错误,应用程序处于未知状态。 大部分像这样(就像上面那样)是因为开发者已经错过了一些东西(对象可以是非null和不可复制的)。

我可能不会使用InternalError除非我非常确定代码是不可访问的(例如,在System.exit() ),因为我比VM更可能犯错。

我只会使用一个自定义的exception(如TotallyFooException ),如果得到的“不可达线”意味着与其他任何地方抛出该exception相同的东西。

您遇到了CloneNotSupportedException ,这意味着您的代码可以处理它。 但是当你捕捉到它之后,当你到达函数结束时,你几乎不知道该怎么做,这意味着你无法处理它。 所以你是对的,在这种情况下,它是一种代码味道,在我看来,意味着你不应该抓到CloneNotSupportedException

我宁愿使用Objects.requireNonNull()来检查参数a是否不为null。 所以当你读取代码的时候,参数不应该是null。

而为了避免检查exception,我将抛出CloneNotSupportedException作为一个RuntimeException

对于这两个你可以添加很好的文字,意图为什么不应该发生这种情况。

 public Object getClone(Object a) { Objects.requireNonNull(a); try { return a.clone(); } catch (CloneNotSupportedException e) { throw new IllegalArgumentException(e); } } 

在这种情况下,我会写

 public Object getClone(SomeInterface a) throws TotallyFooException { // Precondition: "a" should be null or should have a someMethod method that // does not throw a SomeException. if (a == null) { throw new TotallyFooException() ; } else { try { return a.someMethod(); } catch (SomeException e) { throw new IllegalArgumentException(e) ; } } } 

有意思的是,你说“try语句永远不会失败”,但是你仍然不厌其烦地写一个语句e.printStackTrace(); 你声称永远不会被执行。 为什么?

也许你的信念并不那么坚定。 这是好的(在我看来),因为你的信念不是基于你所写的代码,而是期望你的客户不会违反前提条件。 最好是防守性地编程公共方法。

顺便说一下,你的代码不会为我编译。 即使a的types是Cloneable也不能调用a.clone() 。 至lessEclipse的编译器这样说。 expression式a.clone()给出错误

方法clone()对于Cloneabletypes是未定义的

我会为你的具体情况做什么

 public Object getClone(PubliclyCloneable a) throws TotallyFooException { if (a == null) { throw new TotallyFooException(); } else { return a.clone(); } } 

其中PubliclyCloneable由其定义

 interface PubliclyCloneable { public Object clone() ; } 

或者,如果您确实需要参数types为Cloneable ,则至less编译以下内容。

 public static Object getClone(Cloneable a) throws TotallyFooException { // Precondition: "a" should be null or point to an object that can be cloned without // throwing any checked exception. if (a == null) { throw new TotallyFooException(); } else { try { return a.getClass().getMethod("clone").invoke(a) ; } catch( IllegalAccessException e ) { throw new AssertionError(null, e) ; } catch( InvocationTargetException e ) { Throwable t = e.getTargetException() ; if( t instanceof Error ) { // Unchecked exceptions are bubbled throw (Error) t ; } else if( t instanceof RuntimeException ) { // Unchecked exceptions are bubbled throw (RuntimeException) t ; } else { // Checked exceptions indicate a precondition violation. throw new IllegalArgumentException(t) ; } } catch( NoSuchMethodException e ) { throw new AssertionError(null, e) ; } } } 

上面的例子是有效的,非常Java。 但是,我将如何解决OP如何处理这一回报的问题:

 public Object getClone(Cloneable a) throws CloneNotSupportedException { return a.clone(); } 

检查a是否为空是没有好处的。 这是NPE。 打印堆栈跟踪也没有帮助。 不pipe在哪里处理,堆栈跟踪都是一样的。

用无用的空testing和无用的exception处理来代替代码是没有好处的。 通过删除垃圾,返回问题是没有意义的。

(请注意,OP在exception处理中包含了一个bug,这就是为什么需要返回的原因,OP不会错误的使用我提出的方法。)

有一个返回语句只是为了满足语法不好的做法?

正如其他人所提到的,在你的情况下,这实际上并不适用。

为了回答这个问题,虽然Linttypes的程序肯定没有想出来! 我已经看到两个不同的在一个switch语句中对此进行了争论。

  switch (var) { case A: break; default: return; break; // Unreachable code. Coding standard violation? } 

一个人抱怨说没有rest是违反编码标准的。 另一个抱怨说因为它是无法访问的代码所以它是一个。

我注意到这一点,因为两个不同的程序员不断重新检查代码中的添加和删除,然后添加和删除,取决于他们哪天运行的代码分析器。

如果你在这种情况下结束,select一个,并评论exception,这是你自己展现的好forms。 这是最好的和最重要的外卖。

这不是“只是为了满足语法”。 每个代码path导致返回或抛出是语言的语义要求。 此代码不符合。 如果发生exception,则需要执行以下返回。

没有“不好的做法”,或关于一般的编译器。

无论如何,无论是语法还是语义,你都没有任何select。

我会重写这个最后的回报。 伪代码:

 if a == null throw ... // else not needed, if this is reached, a is not null Object b try { b = a.clone } catch ... return b 

没有人提到这一点,所以在这里:

 public static final Object ERROR_OBJECT = ... //... public Object getClone(Cloneable a) throws TotallyFooException { Object ret; if (a == null) throw new TotallyFooException(); //no need for else here try { ret = a.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); //something went wrong! ERROR_OBJECT could also be null ret = ERROR_OBJECT; } return ret; } 

我不喜欢在这个问题里面回答这个问题。

返回null; 是必要的,因为一个exception可能被捕获,但是在这种情况下,因为我们已经检查过它是否为空(假设我们知道我们调用的类支持克隆),所以我们知道try语句永远不会失败。

如果你知道有关input的细节,你知道try语句永远不会失败,那有什么意义呢? 避免try如果你知道事情总是会成功的(尽pipe你可以绝对肯定你的代码库的整个生命周期)。

无论如何,编译器不幸的不是一个心灵读者。 它看到函数及其input,并给出它所具有的信息,它需要在底部return声明。

为了满足语法和避免编译错误(有一个解释它不会被达成的注释),还是有更好的方法来编写类似这样的代码是不好的做法,返回语句是不必要的?

恰恰相反,我build议避免任何编译器警告是一个很好的做法,例如,即使这会花费另一行代码。 在这里不要太在意行数。 通过testingbuild立function的可靠性,然后继续。 假设你可以省略return声明,想象一年后再回到这个代码,然后试图确定底部的return声明是否会引起更多的混淆,而不是一些评论,详细说明了为什么它被忽略的细节,因为假设你可以制作input参数。 return声明很可能会更容易处理。

这就是说,具体关于这个部分:

 try { return a.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } ... //cant be reached, in for syntax return null; 

我觉得在这里处理exception的心态有点奇怪。 你通常想要在你有一些有意义的事情的地方吞下例外,你可以做出回应。

你可以把try/catch看作一个交易机制。 try进行这些更改,如果它们失败,并且我们分支到catch块中,则作为回滚和恢复过程的一部分做出响应(无论在catch块中)作为响应。

在这种情况下,仅仅打印一个堆栈跟踪,然后被迫返回空值不完全是一个事务/恢复的心态。 代码将error handling责任传递给调用getClone所有代码,以手动检查失败。 您可能更喜欢捕获CloneNotSupportedException并将其转换为另一种更有意义的exceptionforms并抛出exception,但您不希望简单地吞下exception并在此情况下返回null,因为这不像事务恢复站点。

您最终会将责任泄漏给调用者,以便以这种方式手动检查和处理失败,抛出exception将会避免这种情况。

这就像是如果你加载一个文件,这是高层次的交易。 你可能有一个try/catch那里。 在trying加载文件的过程中,您可能会克隆对象。 如果在这个高级操作(加载文件)中的任何地方出现故障,通常希望将这些exception抛出回到这个顶级事务try/catch块,以便在加载文件时从错误中正常恢复(无论是由于克隆或其他方面的错误)。 所以我们通常不想在这样的细粒度的地方吞下一个exception,然后返回一个null,例如,因为这样会打败exception的很多价值和目的。 相反,我们希望将exception传播回一个可以有意义处理的地方。

你的例子是不是很好的说明你的问题,如在最后一段所述:

为了满足语法和避免编译错误(有一个解释它不会被达成的注释),还是有更好的方法来编写类似这样的代码是不好的做法,返回语句是不必要的?

一个更好的例子是克隆本身的实现:

  public class A implements Cloneable { public Object clone() { try { return super.clone() ; } catch (CloneNotSupportedException e) { throw new InternalError(e) ; // vm bug. } } } 

这里应该inputcatch子句。 语法或者需要抛出一些东西或者返回一个值。 由于返回的东西没有任何意义,因此使用InternalError来指示严重的VM情况。