我最近被告知我滥用异常来控制应用程序中的流量,所以我这是我试图以某种方式澄清情况.
在我看来,一个方法应该在遇到情况时抛出异常,这种情况无法在内部处理或者可能由调用方更好地处理.
那么 - 是否存在任何特定的规则集,可用于在开发应用程序时回答以下问题:
什么时候应该抛出一个异常,什么时候应该编写具有强大的nothrow保证的代码,这可能只是返回 bool表示成功或失败?
我应该尝试最小化情况的数量,当方法抛出异常时,或者相反,它应该最大化以在处理这些情况时提供灵活性吗?
我应该坚持在开发我的应用程序时使用的框架/运行时设置的异常抛出约定,还是应该包装所有这些调用,以便它们匹配我自己的异常抛出策略?
我还建议使用错误代码进行错误处理,这似乎非常有效,但从语法的角度来看很丑陋(同样,当使用它们时,开发人员失去了为方法指定输出的能力).你怎么看待这件事?
实施例为第三个问题(I用的I/O架构和遇到以下情况):
所描述的框架不使用异常来处理错误,但其他代码确实使用它们.我是否应该将所有可能的失败包裹起来
'???'并在这种情况下抛出异常?或者我应该将方法的签名更改为bool PrepareTheResultingOutputPath仅指示操作是否成功?
public void PrepareTheResultingOutputFile(
String templateFilePath, String outputFilePath)
{
if (!File.Exists(templateFilePath))
// ???
if (!Directory.MakePath(outputFilePath))
// ???
if (File.Exists(outputFilePath))
if (!File.Remove(outputFilePath))
// ???
if (!File.Copy(templateFilePath, outputFilePath)
// ???
}
Run Code Online (Sandbox Code Playgroud)
另一个例子 - 即使.NET Framework不遵循一些严格的异常抛出策略.一些方法被记录为抛出10多种不同的异常类型,包括普通的异常类型NullArgumentException,但其中一些只是返回bool以指示操作的成功或失败.
谢谢!
我正在尝试创建一个整洁的结构,以便理解基于未来的业务逻辑.这是一个示例,其中包含基于异常处理的工作示例:
(for {
// find the user by id, findUser(id) returns Future[Option[User]]
userOpt <- userDao.findUser(userId)
_ = if (!userOpt.isDefined) throw new EntityNotFoundException(classOf[User], userId)
user = userOpt.get
// authenticate it, authenticate(user) returns Future[AuthResult]
authResult <- userDao.authenticate(user)
_ = if (!authResult.ok) throw new AuthFailedException(userId)
// find the good owned by the user, findGood(id) returns Future[Option[Good]]
goodOpt <- goodDao.findGood(goodId)
_ = if (!good.isDefined) throw new EntityNotFoundException(classOf[Good], goodId)
good = goodOpt.get
// check ownership for the user, checkOwnership(user, good) returns Future[Boolean]
ownership <- goodDao.checkOwnership(user, …Run Code Online (Sandbox Code Playgroud) 我刚刚在一个项目中找到:
try
{
myLabel.Text = school.SchoolName;
}
catch
{
myPanel.Visible = false;
}
Run Code Online (Sandbox Code Playgroud)
我想和开发人员谈谈,而不是写这个,说发生null异常(因为school理论上可能是null,不是myLabel)会使计算机发出三次蜂鸣声并睡两秒钟.但是,我想知道我是否错过了关于这一点的规则.显然,这不是try/catch的预期用途,但这是不好的,因为它因性能考虑而无视意图或不好?我觉得这很糟糕,但我想说的不仅仅是"那真的很糟糕".
示例#1:
try { fileChooser.setSelectedFile(new File(filename)); }
catch (NullPointerException e) { /* do nothing */ }
示例#2:
if (filename != null)
fileChooser.setSelectedFile(new File(filename));
出于性能或稳定性(或任何其他原因),#1本质上是不好的,还是只是有点不同?这不是一个很好的例子,因为#1优于#2没有优势,但在不同情况下可能存在(例如,可读性提高,代码行数减少等).
编辑:共识似乎是#1是禁忌.最受欢迎的原因:开销
此外,@ Raph Levien有一个很好的见解:
避免#1的一个原因是它会中毒你使用异常断点的能力.正常运行的代码永远不会故意触发空指针异常.因此,将调试器设置为每次发生时都停止是有意义的.在#1的情况下,您可能会例行地获得此类异常.除其他正当理由外,还有潜在的性能影响.
另外,请参阅链接以获取更多深度.
我总是在错误的背景下看到Throwable/Exception.但是我可以想到扩展一个Throwablejust来打破一堆递归方法调用会非常好的情况.比如说,您试图通过递归搜索的方式在树中查找并返回一些对象.一旦你发现它粘在一些Carrier extends Throwable并抛出它,并在调用递归方法的方法中捕获它.
正面:您不必担心递归调用的返回逻辑; 既然你找到了你需要的东西,为什么还要担心如何将这个引用备份到方法堆栈中.
否定:您有一个不需要的堆栈跟踪.该try/catch块也变得违反直觉.
这是一个愚蠢的简单用法:
public class ThrowableDriver {
public static void main(String[] args) {
ThrowableTester tt = new ThrowableTester();
try {
tt.rec();
} catch (TestThrowable e) {
System.out.print("All good\n");
}
}
}
public class TestThrowable extends Throwable {
}
public class ThrowableTester {
int i=0;
void rec() throws TestThrowable {
if(i == 10) throw new TestThrowable();
i++;
rec();
}
}
Run Code Online (Sandbox Code Playgroud)
问题是,是否有更好的方法来达到同样的目的?另外,以这种方式做事有什么不妥之处吗?
我有两个不同的函数实现(例如,树的大小),一个是递归的,另一个是使用显式堆栈.
递归非常快(可能是因为它不需要在堆上分配任何东西)但可能会导致某些"罕见"输入上的堆栈溢出(在树的例子中,它将出现在任何不平衡的树上).显式版本较慢但不太可能导致堆栈溢出.
默认情况下使用递归实现是否安全,并通过执行显式实现从StackOverflowError异常中恢复?
这被认为是不好的做法吗?
这是一个代码的小例子:
interface Node {
List<? extends Node> getSons();
}
static int sizeRec (Node root) {
int result = 1;
for (Node son : root.getSons()) {
result += sizeRec(son);
}
return result;
}
static int sizeStack (Node root) {
Stack<Node> stack = new Stack<Node>();
stack.add(root);
int size = 0;
while (! stack.isEmpty()) {
Node x = stack.pop();
size ++;
for (Node son : x.getSons()) {
stack.push(son);
}
}
return size;
}
static int size (Node root) { …Run Code Online (Sandbox Code Playgroud) 我有一个Users表,它对用户名有唯一约束(出于显而易见的原因).
我正在使用EF 4.0 DAL来填充数据库,并在编写CreateUser()方法的过程中.
是吗...
如果你也可以说明原因,那就太好了!
.net c# entity-framework exception-handling sql-server-2008-r2
让我们想象一下,我们有一个进程,它接受以下类型的数据:
{"date":"2014-05-05", "url":"http://some.website.com","counter":3}
Run Code Online (Sandbox Code Playgroud)
date应该是一个可解析的日期,url也应该符合正常的 url 语法。date应该在未来,url应该是一个可访问的地址,返回200 OK.为了使它干净,必须将这两个验证例程分成不同的单元(类、实用程序等)。然而,所需的最终行为必须让用户清楚地了解数据中存在的所有违规行为。就像是:
{"Errors":[
"Specified date is not in the future",//Formal validation failed
"Specified URL has invalid syntax"//Logical validation failed
]}
Error对象的实现,并且充满了像Error.hasErrors()or之类的检查
error==null,这看起来并不优雅。javax.validation,它同时为您提供所有领域的所有违规行为。可以为内容验证实施相同的方法,但我不确定这是执行此操作的最佳方法。问题:处理各种性质的多个异常/违规的最佳做法是什么?
UPD:答案的简短摘要: collect Violations, build an Exception,包含它们的上下文、原因和描述,使用拦截器进行渲染。请参阅答案中的参考链接:
http://beanvalidation.org/1.0/spec/ JSR 303 规范
http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/validation.html Spring Bean 验证
http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html Java EE 验证
在 Python 中,如果我有一个 dict,并且我想从一个可能不存在密钥的 dict 中获取一个值,我会执行以下操作:
lookupValue = somedict.get(someKey, someDefaultValue)
Run Code Online (Sandbox Code Playgroud)
其中,如果someKey不存在,则someDefaultValue返回。
在 C# 中,有些TryGetValue()类似:
var lookupValue;
if(!somedict.TryGetValue(someKey, lookupValue))
lookupValue = someDefaultValue;
Run Code Online (Sandbox Code Playgroud)
一个问题是,如果someKey是null然后抛出异常,所以你进行了空检查:
var lookupValue = someDefaultValue;
if (someKey != null && !somedict.TryGetValue(someKey, lookupValue))
lookupValue = someDefaultValue;
Run Code Online (Sandbox Code Playgroud)
哪个,TBH,是 icky(3 行用于 dict 查找?)有没有更简洁(即 1 行)的方式,很像 Python 的get()?
看到这个问题,每个人都谈论"性能"会如何受到影响,或者当性能成为问题时应该避免例外,等等.
但是我没有看到一个很好的解释,为什么抛出异常对性能不利,这个问题中的每个人似乎都认为这是理所当然的.
我问这个的原因是,我正在尝试优化一个应用程序,并注意到在某些操作上抛出并吞下了几百个异常,例如单击按钮来加载新页面.
java ×5
c# ×3
exception ×2
try-catch ×2
.net ×1
dictionary ×1
future ×1
performance ×1
python ×1
scala ×1
stack ×1
throw ×1
throwable ×1
validation ×1