java Java中的LBYL与EAFP?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/404795/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 12:15:13  来源:igfitidea点击:

LBYL vs EAFP in Java?

javapythonerror-handlingidioms

提问by ryeguy

I was recently teaching myself Python and discovered the LBYL/EAFP idioms with regards to error checking before code execution. In Python, it seems the accepted style is EAFP, and it seems to work well with the language.

我最近在自学 Python,并发现了 LBYL/EAFP 习语关于代码执行前的错误检查。在 Python 中,似乎接受的风格是 EAFP,并且它似乎与该语言配合得很好。

LBYL (Look Before You Leap):

LBYL(大号OOK安伏ýOU大号EAP):

def safe_divide_1(x, y):
    if y == 0:
        print "Divide-by-0 attempt detected"
        return None
    else:
        return x/y

EAFP (it's Easier to Ask Forgiveness than Permission):

EAFP(这是êasier到一个SK ˚Forgiveness比Permission):

def safe_divide_2(x, y):
    try:
        return x/y
    except ZeroDivisionError:  
        print "Divide-by-0 attempt detected"
        return None

My question is this: I had never even heard of using EAFP as the primary data validation construct, coming from a Java and C++ background. Is EAFP something that is wise to use in Java? Or is there too much overhead from exceptions? I know that there is only overhead when an exception is actually thrown, so I'm unsure as to why the simpler method of EAFP is not used. Is it just preference?

我的问题是:我从来没有听说过使用 EAFP 作为主要数据验证构造,来自 Java 和 C++ 背景。在 Java 中使用 EAFP 是否明智?还是异常带来的开销太大?我知道只有在实际抛出异常时才会产生开销,所以我不确定为什么不使用更简单的 EAFP 方法。仅仅是偏好吗?

采纳答案by Yuval Adam

Personally, and I think this is backed up by convention, EAFP is never a good way to go. You can look at it as an equivalent to the following:

就我个人而言,我认为这是由惯例支持的,EAFP 从来都不是一个好方法。您可以将其视为等效于以下内容:

if (o != null)
    o.doSomething();
else
    // handle

as opposed to:

与:

try {
    o.doSomething()
}
catch (NullPointerException npe) { 
    // handle
}

Moreover, consider the following:

此外,请考虑以下事项:

if (a != null)
    if (b != null)
        if (c != null)
            a.getB().getC().doSomething();
        else
            // handle c null
    else
        // handle b null
else
    // handle a null

This may look a lot less elegant (and yes this is a crude example - bear with me), but it gives you much greater granularity in handling the error, as opposed to wrapping it all in a try-catch to get that NullPointerException, and then try to figure out where and why you got it.

这可能看起来不那么优雅(是的,这是一个粗略的例子 - 请耐心等待),但它在处理错误时为您提供了更大的粒度,而不是将其全部包装在 try-catch 中以获取该错误NullPointerException,然后试着弄清楚你在哪里以及为什么得到它。

The way I see it EAFP should never be used, except for rare situations. Also, since you raised the issue: yes, the try-catch block does incur some overheadeven if the exception is not thrown.

在我看来,永远不应该使用 EAFP,除非是极少数情况。此外,由于您提出了这个问题:是的,即使没有抛出异常,try-catch 块也会产生一些开销

回答by Jonathan Leffler

If you are accessing files, EAFP is more reliable than LBYL, because the operations involved in LBYL are not atomic, and the file system might change between the time you look and the time you leap. Actually, the standard name is TOCTOU - Time of Check, Time of Use; bugs caused by inaccurate checking are TOCTOU bugs.

如果您正在访问文件,EAFP 比 LBYL 更可靠,因为 LBYL 中涉及的操作不是原子的,并且文件系统可能会在您查看和跳转之间发生变化。实际上,标准名称是TOCTOU - Time of Check, Time of Use;检查不准确导致的错误是TOCTOU错误。

Consider creating a temporary file that must have a unique name. The best way to find out whether the chosen file name exists yet is to try creating it - making sure you use options to ensure that your operation fails if the file does already exist (in POSIX/Unix terms, the O_EXCL flag to open()). If you try to test whether the file already exists (probably using access()), then between the time when that says "No" and the time you try to create the file, someone or something else may have created the file.

考虑创建一个必须具有唯一名称的临时文件。确定所选文件名是否存在的最佳方法是尝试创建它 - 确保您使用选项来确保如果文件已经存在则操作失败(在 POSIX/Unix 术语中,O_EXCL 标志为open())。如果您尝试测试文件是否已经存在(可能使用access()),那么在显示“否”和您尝试创建文件的时间之间,可能是有人或其他东西创建了该文件。

Conversely, suppose that you try to read an existing file. Your check that the file exists (LBYL) may say "it is there", but when you actually open it, you find "it is not there".

相反,假设您尝试读取现有文件。您检查文件是否存在 (LBYL) 可能会说“它在那里”,但是当您实际打开它时,您会发现“它不在那里”。

In both these cases, you have to check the final operation - and the LBYL didn't automatically help.

在这两种情况下,您都必须检查最终操作 - 而 LBYL 并没有自动提供帮助。

(If you are messing with SUID or SGID programs, access()asks a different question; it may be relevant to LBYL, but the code still has to take into account the possibility of failure.)

(如果您正在使用 SUID 或 SGID 程序,access()请提出不同的问题;它可能与 LBYL 相关,但代码仍然必须考虑失败的可能性。)

回答by Jeff Shannon

In addition to the relative cost of exceptions in Python and Java, keep in mind that there's a difference in philosophy / attitude between them. Java tries to be very strict about types (and everything else), requiring explicit, detailed declarations of class/method signatures. It assumes that you should know, at any point, exactly what type of object you're using and what it is capable of doing. In contrast, Python's "duck typing" means that you don't know for sure (and shouldn't care) what the manifest type of an object is, you only need to care that it quacks when you ask it to. In this kind of permissive environment, the only sane attitude is to presume that things will work, but be ready to deal with the consequences if they don't. Java's natural restrictiveness doesn't fit well with such a casual approach. (This is not intended to disparage either approach or language, but rather to say that these attitudes are part of each language's idiom, and copying idioms between different languages can often lead to awkwardness and poor communication...)

除了 Python 和 Java 中异常的相对成本之外,请记住,它们之间在哲学/态度上存在差异。Java 试图对类型(以及其他所有内容)非常严格,要求对类/方法签名进行明确、详细的声明。它假设您在任何时候都应该确切地知道您正在使用什么类型的对象以及它能够做什么。相比之下,Python 的“鸭子类型”意味着你不确定(也不应该关心)一个对象的清单类型是什么,你只需要关心当你要求它时它会发出嘎嘎声。在这种宽容的环境中,唯一理智的态度是假设事情会奏效,但准备好应对失败的后果。Java 的自然限制不 很适合这种随意的方法。(这不是要贬低方法或语言,而是要说这些态度是每种语言习语的一部分,在不同语言之间复制习语往往会导致尴尬和沟通不畅......)

回答by mipadi

Exceptions are handled more efficiently in Python than in Java, which is at least partlywhy you see that construct in Python. In Java, it's more inefficient (in terms of performance) to use exceptions in that way.

与 Java 相比,Python 中的异常处理效率更高,这至少您在 Python 中看到该构造的部分原因。在 Java 中,以这种方式使用异常效率更低(就性能而言)。

回答by Veedrac

Consider these code snippets:

考虑这些代码片段:

def int_or_default(x, default=0):
    if x.isdigit():
        return int(x)
    else:
        return default

def int_or_default(x, default=0):
    try:
        return int(x)
    except ValueError:
        return default

They both look correct, right? But one of them isn't.

他们看起来都正确,对吧?但其中之一不是。

The former, using LBYL, fails because of a subtle distinction between isdigitand isdecimal; when called with the string "①23?", it will throw an error rather than correctly return the default value.

前者使用 LBYL,由于 和 之间的细微区别isdigit而失败isdecimal;当使用字符串“①23?”调用时,它会抛出错误而不是正确返回默认值。

The later, using EAFTP, results in correct handling, by definition. There is no scope for a behavioural mismatch, because the code that needs the requirement isthe code that asserts that requirement.

根据定义,后者使用 EAFTP 会导致正确处理。没有余地行为不匹配,因为需要要求的代码断言要求的代码。

Using LBYL means taking internal logic and copying them into everycall-site. Rather than having one canonical encoding of your requirements, you get a free chance to mess up every single time you call the function.

使用 LBYL 意味着获取内部逻辑并将它们复制到每个调用站点。不是对您的需求进行一种规范编码,而是在每次调用该函数时都有机会搞砸。

It's worth noting that EAFTP isn'tabout exceptions, and Java code especially should not be using exceptions pervasively. It is about giving the right job to the right block of code. As an example, using Optionalreturn values is a perfectly valid way of writing EAFTP code, and is far more effective for ensuring correctness than LBYL.

值得一提的是,EAFTP不是有关异常,和Java代码尤其是不应该被普遍地使用异常。它是关于为正确的代码块提供正确的工作。例如,使用Optional返回值是编写 EAFTP 代码的一种完全有效的方式,并且在确保正确性方面比 LBYL 有效得多。