Java 当 catch 实际上没有捕获任何东西时
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/50378884/
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
When catch doesn't actually catch anything
提问by Bob Stout
I had a program crash because of bad data stored in a database recently. This confused me, because I thought I had a catch to prevent this.
由于最近存储在数据库中的数据错误,我的程序崩溃了。这让我很困惑,因为我认为我有办法防止这种情况发生。
The intent of the following code is to compare employee badge numbers and sort them. If there's an error, return -1 and soldier on -- don't stop because one of several thousand badge numbers is wrong:
以下代码的目的是比较员工徽章编号并对其进行排序。如果出现错误,则返回 -1 并继续前进——不要因为数千个徽章编号中的一个错误而停止:
public int compare(Employee t, Employee t1) {
Integer returnValue = -1;
try {
Integer tb = Integer.parseInt(t.getBadgeNumber());
Integer t1b = Integer.parseInt(t1.getBadgeNumber());
returnValue = tb.compareTo(t1b);
} catch (Exception e) {
returnValue = -1;//useless statement, I know.
}
return returnValue;
}
When the bad badge number hit (as t in this case), I got an "java.lang.IllegalArgumentException: Comparison method violates its general contract!" error instead of returning the -1 in the catch.
当错误的徽章编号命中时(如本例中的 t),我得到了一个“java.lang.IllegalArgumentException:比较方法违反了它的一般契约!” 错误而不是在捕获中返回 -1。
What don't I understand about the catch here?
我不明白这里的捕获是什么?
The full stacktrace:
完整的堆栈跟踪:
16-May-2018 14:28:53.496 SEVERE [http-nio-8084-exec-601] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [RequestServlet] in context with path [/AppearanceRequest] threw exception
java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(TimSort.java:868)
at java.util.TimSort.mergeAt(TimSort.java:485)
at java.util.TimSort.mergeForceCollapse(TimSort.java:426)
at java.util.TimSort.sort(TimSort.java:223)
at java.util.TimSort.sort(TimSort.java:173)
at java.util.Arrays.sort(Arrays.java:659)
at java.util.Collections.sort(Collections.java:217)
at org.bcso.com.appearancerequest.html.NotifierHTML.getHTML(NotifierHTML.java:363)
at org.bcso.com.appearancerequest.AppearanceRequestServlet.processRequest(AppearanceRequestServlet.java:96)
at org.bcso.com.appearancerequest.AppearanceRequestServlet.doGet(AppearanceRequestServlet.java:565)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:301)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:136)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:74)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:516)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1015)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:652)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1575)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1533)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
The calling code:
调用代码:
List<Employee> employeeList = DatabaseUtil.getEmployees();
Collections.sort(employeeList, new BadgeComparator());
采纳答案by rgettman
The exception (whatever it was) wascaught by catch (Exception e)
. You didn't log this exception, so you don't know what it was. You should log it somehow so you know what really happened.
唯一的例外(不管它是什么)是通过抓catch (Exception e)
。你没有记录这个异常,所以你不知道它是什么。你应该以某种方式记录它,以便你知道真正发生了什么。
The problem occurs when you return -1
. This allows for the possibility of inconsistent ordering, which Java's current sorting algorithm sometimes catches. In short, returning -1
on an error means that you are asserting that both a < b
and b < a
are true, because the exception will be caught in both cases. This is logically incorrect. The sorting algorithm detects this and throws the IllegalArgumentException
. Note that the compare
method is notin your stack trace; it's the call to Collections.sort
.
返回时出现问题-1
。这允许不一致排序的可能性,Java 当前的排序算法有时会捕获这种情况。简而言之,返回-1
错误意味着您断言a < b
和b < a
都是真的,因为在这两种情况下都会捕获异常。这在逻辑上是不正确的。排序算法检测到这一点并抛出IllegalArgumentException
. 请注意,该compare
方法不在您的堆栈跟踪中;这是对 的调用Collections.sort
。
In addition to logging the exception, handle it before you even get to the comparison step in your program. If you have to parse the string as an integer, do that when creating the Employee
objects, so that the validation occurs before you even get to the sorting step in your program. A Comparator
shouldn't have to validate data; it should only compare the data.
除了记录异常之外,还要在进入程序中的比较步骤之前处理它。如果您必须将字符串解析为整数,请在创建Employee
对象时执行此操作,以便在您进入程序中的排序步骤之前进行验证。AComparator
不应该验证数据;它应该只比较数据。
回答by davidxxx
The exception is thrown from TimSort.mergeHi()
invoked internally as you explicitly invoked Collections.sort()
:
TimSort.mergeHi()
当您显式调用时,从内部调用引发异常Collections.sort()
:
at java.util.TimSort.mergeHi(TimSort.java:868)
在 java.util.TimSort.mergeHi(TimSort.java:868)
You could move the catch statement around sort()
but as a consequence the sort will not be performed or be no complete. So it seems not to be a good idea.
Long story short : don't violate the compareTo()
contract and you would not need to catch any exception that will not happen any longer.
您可以移动 catch 语句,sort()
但结果是排序不会执行或不完整。所以这似乎不是一个好主意。
长话短说:不要违反compareTo()
合同,您将不需要捕获任何不会再发生的异常。
回答by Zabuzard
Explanation
解释
java.lang.IllegalArgumentException: Comparison method violatesits general contract!
java.lang.IllegalArgumentException:比较方法违反了它的一般约定!
The exception is not thrown from within your try
. That is why it is not caught. The exception comes from NotifierHTML.java:363
in your code where you call Collection#sort
which uses a TimSort
class. The exception is then thrown from TimSort.java:868
by the TimSort#mergeHi
method.
异常不会从您的try
. 这就是它不被捕获的原因。异常来自NotifierHTML.java:363
您调用Collection#sort
使用TimSort
类的代码。然后TimSort.java:868
该TimSort#mergeHi
方法抛出异常。
It tells you that your implementation of the Comparator#compare
method is wrong. It violates the contract, as explained in its documentation:
它告诉你你的Comparator#compare
方法实现是错误的。它违反了合同,如其文档中所述:
Compares its two arguments for order. Returns a negativeinteger, zero, or a positiveinteger as the first argument is less than, equal to, or greater thanthe second.
The implementor must ensure
sgn(x.compareTo(y)) == -sgn(y.compareTo(x))
for allx
andy
. (This implies thatx.compareTo(y)
must throw an exception iffy.compareTo(x)
throws an exception.)The implementor must also ensurethat the relation is transitive:
(x.compareTo(y) > 0 && y.compareTo(z) > 0)
impliesx.compareTo(z) > 0
.Finally, the implementor must ensurethat
x.compareTo(y) == 0
implies thatsgn(x.compareTo(z)) == sgn(y.compareTo(z))
, for allz
.
比较它的两个参数的顺序。当第一个参数小于、等于或大于第二个参数时,返回一个负整数、零或正整数。
实现者必须确保
sgn(x.compareTo(y)) == -sgn(y.compareTo(x))
所有x
和y
. (这意味着x.compareTo(y)
如果y.compareTo(x)
抛出异常,则必须抛出异常。)实现者还必须确保关系是可传递的:
(x.compareTo(y) > 0 && y.compareTo(z) > 0)
暗示x.compareTo(z) > 0
。最后,实现者必须确保这
x.compareTo(y) == 0
意味着sgn(x.compareTo(z)) == sgn(y.compareTo(z))
,对于所有z
.
Your implementation violates one of those requirements and the method detected that.
您的实现违反了其中一项要求,并且该方法检测到了这一点。
Source of the problem
问题的根源
The problem is that you return -1
if an error occurs. Suppose you have two values first
and second
. And that at least one of them will provoke the exception.
问题是-1
如果发生错误,您将返回。假设您有两个值first
和second
。并且其中至少有一个会引发异常。
So if you want to compare first
with second
, you get -1
:
所以,如果你想比较first
有second
,你会得到-1
:
compare(first, second) -> -1
Which means that first
is smallerthan second
. But if you compare it the other way you get -1
too:
这意味着first
是小比second
。但是如果你用另一种方式比较它,你-1
也会得到:
compare(second, first) -> -1
Because the exception is thrown in both variants, which leads to your return -1;
. But this means your compare
method says:
因为在两个变体中都抛出了异常,这会导致您的return -1;
. 但这意味着您的compare
方法说:
first < second
second < first
Both at the same time, which is logically incorrect and violates the contract.
两者同时存在,这在逻辑上是不正确的,并且违反了合同。
Solution
解决方案
You need to correctly define where in your ordering unparsable content is placed at. For example let us define that it is always smaller than any number. So we want
您需要正确定义排序中不可解析内容的放置位置。例如,让我们定义它总是小于任何数字。所以我们想要
text < number
What do we do if both are unparsable? We could say they are equal, we could compare them lexicographical. Let's keep it simple and say that any two texts are considered equal:
如果两者都不可解析,我们该怎么办?我们可以说它们是平等的,我们可以按字典顺序比较它们。让我们保持简单,假设任何两个文本都被认为是相等的:
text = text
We implement this by checking which of the arguments are unparseable and then returning the correct value:
我们通过检查哪些参数是不可解析的,然后返回正确的值来实现这一点:
@Override
public int compare(Employee first, Employee second) {
Integer firstValue;
Integer secondValue;
try {
firstValue = Integer.parseInt(first.getBadgeNumber());
} catch (NumberFormatException e) {
// Could not parse, set null as indicator
firstValue = null;
}
try {
secondValue = Integer.parseInt(second.getBadgeNumber());
} catch (NumberFormatException e) {
// Could not parse, set null as indicator
secondValue = null;
}
if (firstValue == null && secondValue != null) {
// text < number
return -1;
}
if (firstValue != null && secondValue == null) {
// number > text
return 1;
}
if (firstValue == null && secondValue == null) {
// text = text
return 0;
}
// Both are numbers
return Integer.compare(firstValue, secondValue);
}
As hinted in the comments you could replace your whole custom Comparator
class by the following statement which generates the same Comparator:
正如评论中所暗示的,您可以用Comparator
以下生成相同比较器的语句替换整个自定义类:
Comparator<Employee> comp = Comparator.nullsLast(
Comparator.comparing(e -> tryParseInteger(e.getBadgeNumber())));
Together with a tryParseInteger
method like this:
连同这样的tryParseInteger
方法:
public static Integer tryParseInteger(String text) {
try {
return Integer.parseInt(text);
} catch (NumberFormatException e) {
return null;
}
}
回答by Antoniossss
That exception is not thrown in comparemethod you pasted here. Check the stacktrace. There is no compare
call in it.
您在此处粘贴的比较方法中不会引发该异常。检查堆栈跟踪。里面没有compare
电话。
回答by Dariusz
While this is not the case, remember that you can throw and catch Throwableinstances, and apart from Exceptions there are Errors. Catching them is possible, though when they occur its unlikely that any further work can be done.
虽然情况并非如此,但请记住,您可以抛出和捕获Throwable实例,除了 Exceptions 之外,还有Errors。抓住它们是可能的,但当它们发生时,就不太可能进行任何进一步的工作。
So your try-catch would not have caught an Error or any Throwable other than Exception.
因此,您的 try-catch 不会捕获错误或除异常以外的任何 Throwable。
public static void main(String[] args) {
try {
throw new Error("test exception try-catch");
} catch (Throwable e) {
System.out.println("Error caught in throwable catch");
}
try {
throw new Error("test exception try-catch");
} catch (Exception e) {
System.out.println("Error caught in exception catch");
}
}
Which will result in:
这将导致:
Error caught in throwable catch
Exception in thread "main" java.lang.Error: test exception try-catch
at ...