英文:
Best practices for passing same exception to call via stream
问题
以下是您要求的代码部分的翻译:
我有一个抛出MyOwnException的方法,但我们都知道在流内部调用时建议使用RunTimeException进行包装。这是我实现的代码:
package com.company;
import java.util.Arrays;
import java.util.List;
public class Main {
static class MyOwnException extends Exception {
}
public static void main(String[] args) throws MyOwnException {
// write your code here
List<String> input = Arrays.asList("bad", "ok");
try {
long i = input.parallelStream().map(s -> tryIfBadStringThrowExceptionIdentity(s)).count();
}
catch (RuntimeException re) {
String s = re.getMessage();
if(s.equalsIgnoreCase("MyOwnException"))
throw new MyOwnException();
}
}
private static String ifBadStringThrowExceptionIdentity(String s) throws MyOwnException {
if(s.equalsIgnoreCase("bad"))
throw new MyOwnException();
else return s;
}
private static String tryIfBadStringThrowExceptionIdentity(String s) {
try {
return ifBadStringThrowExceptionIdentity(s);
} catch (MyOwnException e) {
throw new RuntimeException("MyOwnException");
}
}
}
通过字符串传递,然后再通过字符串创建异常,这是最佳实践吗?还是您有一些更优雅的解决方案?如果这是最佳方法,是不是只有我开始不喜欢Java?另外,为什么只有RunTimeException在流相关的异常中有效?将字符串转换回异常会影响代码速度吗?
英文:
I have one method throwing MyOwnException, but we all know that it is suggested to wrap it with RunTimeException when we are calling within streams. So here is the implementation I have done:
package com.company;
import java.util.Arrays;
import java.util.List;
public class Main {
static class MyOwnException extends Exception {
}
public static void main(String[] args) throws MyOwnException {
// write your code here
List<String> input = Arrays.asList("bad", "ok");
try {
long i = input.parallelStream().map(s -> tryIfBadStringThrowExceptionIdentity(s)).count();
}
catch (RuntimeException re) {
String s = re.getMessage();
if(s.equalsIgnoreCase("MyOwnException"))
throw new MyOwnException();
}
}
private static String ifBadStringThrowExceptionIdentity(String s) throws MyOwnException {
if(s.equalsIgnoreCase("bad"))
throw new MyOwnException();
else return s;
}
private static String tryIfBadStringThrowExceptionIdentity(String s) {
try {
return ifBadStringThrowExceptionIdentity(s);
} catch (MyOwnException e) {
throw new RuntimeException("MyOwnException");
}
}
}
Passing string and then again creating exception back via the string, is it best practices, or you have some elegant solution to this? if this is best way, am I the only one started disliking Java? And by the way, why only RunTimeException is valid for Streams related exception, does it impact code speed converting string back to exception?
答案1
得分: 1
不要使用现有的异常类型,比如RuntimeException
,因为它可能有其他的原因,也不要依赖于像字符串这样脆弱的东西来识别问题。只需使用专门的异常类型来携带底层的已检查异常到发起者:
static class UncheckedMyOwnException extends RuntimeException {
UncheckedMyOwnException(MyOwnException original) {
super(original);
}
@Override
public MyOwnException getCause() {
return (MyOwnException)super.getCause();
}
}
public static void main(String[] args) throws MyOwnException {
List<String> input = Arrays.asList("bad", "ok");
try {
// 不要依赖于 count() 进行处理代码;从 JDK 9 开始,它将跳过不需要确定计数的映射操作
input.parallelStream().map(s -> tryIfBadStringThrowExceptionIdentity(s))
.forEach(System.out::println);
}
catch(UncheckedMyOwnException re) {
throw re.getCause();
}
}
private static String ifBadStringThrowExceptionIdentity(String s) throws MyOwnException {
if(s.equalsIgnoreCase("bad"))
throw new MyOwnException();
else return s;
}
private static String tryIfBadStringThrowExceptionIdentity(String s) {
try {
return ifBadStringThrowExceptionIdentity(s);
} catch(MyOwnException e) {
throw new UncheckedMyOwnException(e);
}
}
请注意,这将抛出原始异常,因此在堆栈跟踪中包含了实际的起源。但是当异常发生在工作线程中时,它将不会包括发起者,即启动流操作的调用链。为了确保这两部分始终被包括在内,您必须使用类似以下的方式:
catch(UncheckedMyOwnException re) {
MyOwnException withInitiator = new MyOwnException();
withInitiator.initCause(re.getCause());
throw withInitiator;
}
使用专门的未检查异常类型来携带已检查异常是一种已经确立的模式,例如UncheckedIOException
。
英文:
Do not use an existing exception type like RuntimeException
that can have other causes and don’t rely on something as fragile as strings for identifying your issue. Just use a dedicated exception type for carrying an underlying checked exception to the initiator:
static class UncheckedMyOwnException extends RuntimeException {
UncheckedMyOwnException(MyOwnException original) {
super(original);
}
@Override
public MyOwnException getCause() {
return (MyOwnException)super.getCause();
}
}
public static void main(String[] args) throws MyOwnException {
List<String> input = Arrays.asList("bad", "ok");
try {
// do not rely on count() for processing code; starting with JDK 9 it will skip
// map operations not needed to determine the count
input.parallelStream().map(s -> tryIfBadStringThrowExceptionIdentity(s))
.forEach(System.out::println);
}
catch(UncheckedMyOwnException re) {
throw re.getCause();
}
}
private static String ifBadStringThrowExceptionIdentity(String s) throws MyOwnException {
if(s.equalsIgnoreCase("bad"))
throw new MyOwnException();
else return s;
}
private static String tryIfBadStringThrowExceptionIdentity(String s) {
try {
return ifBadStringThrowExceptionIdentity(s);
} catch(MyOwnException e) {
throw new UncheckedMyOwnException(e);
}
}
Note that this will throw the original exception, so it includes the actual origin in its stack trace. But when the exception happened in a worker thread, it will not include the initiator, i.e. the call chain that started the stream operation. To ensure that both parts are always included, you would have to use something like
catch(UncheckedMyOwnException re) {
MyOwnException withInitiator = new MyOwnException();
withInitiator.initCause(re.getCause());
throw withInitiator;
}
Using a dedicated unchecked exception type to carry a checked exception, is an established pattern, see for example UncheckedIOException
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论