Java8流。向lamba表达式内的客户端方法抛出异常
我看到了一些与此相关的问题,但我需要一个明确的答案。我确实理解lamba表达式运行的上下文,以及副作用的概念,但我相信有一个解决方法我在这里没有看到 我需要根据人物角色的性别映射一个列表,但是我用来确定他们性别的方法返回一个选中的异常,这根本不是Collectors.groupingBy喜欢的 清除选中的异常不是一个选项,我需要将它发送给调用我的代码片段的客户机方法。我能做点什么吗Java8流。向lamba表达式内的客户端方法抛出异常,java,lambda,java-8,java-stream,Java,Lambda,Java 8,Java Stream,我看到了一些与此相关的问题,但我需要一个明确的答案。我确实理解lamba表达式运行的上下文,以及副作用的概念,但我相信有一个解决方法我在这里没有看到 我需要根据人物角色的性别映射一个列表,但是我用来确定他们性别的方法返回一个选中的异常,这根本不是Collectors.groupingBy喜欢的 清除选中的异常不是一个选项,我需要将它发送给调用我的代码片段的客户机方法。我能做点什么吗 public class Example { public static void main(String[]
public class Example {
public static void main(String[] args) {
Example example = new Example();
try {
example.runExample();
} catch (MException e) {
//Place where I want to handle the exception
}
}
private void runExample() throws MException{
List<Person> personas = Arrays.asList(new Person("Sergio", "234456789", 35), new Person("Mariana", "123456789", 38));
Map<String, List<Person>> personsBySex = personas.stream().collect(Collectors.groupingBy(persona -> {
try {
return getSex(persona.getSSN());
} catch (MException e) {
}
return null;
//Compiler forces me to return a value, but I don't want to return null.
//I want to throw up the MException to the client method (main)
}));
}
private String getSex(String ssn) throws MException {
// Imagine here is a call to an outside service that would give me the
// sex based on the SSN, but this service could return an exception as
// well
if (ssn.isEmpty())
throw new MException();
return ssn.startsWith("1") ? "Female" : "Male";
}
}
class Person {
private String name, ssn;
private Integer age;
public Person(String name, String ssn, Integer age) {
this.name = name;
this.ssn = ssn;
this.age = age;
}
public String getName() {return name;}
public String getSSN() {return ssn;}
public Integer getAge() {return age;}
}
class MException extends Exception {
}
公共类示例{
公共静态void main(字符串[]args){
示例=新示例();
试一试{
runExample();
}捕获(MException e){
//我要处理异常的位置
}
}
private void runExample()引发MeException{
listpersonas=Arrays.asList(新人(“塞尔吉奥”,“234456789”,35),新人(“玛丽安娜”,“123456789”,38));
Map personsBySex=personas.stream().collect(Collectors.groupingBy(persona->{
试一试{
返回getSex(persona.getSSN());
}捕获(MException e){
}
返回null;
//编译器强制我返回一个值,但我不想返回null。
//我想向客户机方法抛出MException(main)
}));
}
私有字符串getSex(字符串ssn)抛出MException{
//想象一下,这是一个打给外部服务的电话,它会给我
//sex基于SSN,但此服务可能会返回异常作为
//嗯
if(ssn.isEmpty())
抛出新的MException();
返回ssn.startsWith(“1”)?“女性”:“男性”;
}
}
班主任{
私有字符串名称,ssn;
私人整数年龄;
公众人物(字符串名称、字符串ssn、整数年龄){
this.name=名称;
这个.ssn=ssn;
这个。年龄=年龄;
}
公共字符串getName(){return name;}
公共字符串getSSN(){return ssn;}
公共整数getAge(){return age;}
}
类MException扩展了异常{
}
谢谢你的建议 解决方法可以是将选中的异常包装为未选中的异常,然后从
catch
块中抛出后者。请注意,我们正在保存一个MException
,以便能够进一步处理
try {
return getSex(persona.getSSN());
} catch (MException e) {
throw new IllegalArgumentException(e); // choose a suitable runtime one
}
另一种方法是编写一个收集器。groupingBy
-友好的方法将上述逻辑转换为:
private String getSexFriendly(String ssn) {
try {
return getSex(ssn);
} catch (MException e) {
throw new IllegalArgumentException(e);
}
}
不过,我们会有一个好看的兰姆达:
persona -> getSexFriendly(persona.getSSN())
解决方法可以是将选中的异常包装为未选中的异常,然后从
catch
块抛出后者。请注意,我们正在保存一个MException
,以便能够进一步处理
try {
return getSex(persona.getSSN());
} catch (MException e) {
throw new IllegalArgumentException(e); // choose a suitable runtime one
}
另一种方法是编写一个收集器。groupingBy
-友好的方法将上述逻辑转换为:
private String getSexFriendly(String ssn) {
try {
return getSex(ssn);
} catch (MException e) {
throw new IllegalArgumentException(e);
}
}
不过,我们会有一个好看的兰姆达:
persona -> getSexFriendly(persona.getSSN())
忘记包装您的异常-您可以利用这里的“偷偷抛出”攻击,这使您能够欺骗编译器认为您的异常未被检查-这利用了Java 8中引入的类型推断规则 让我们重新创建您的问题:
public Integer toInteger(String string) throws IOException {
throw new IOException("whoopsie!");
}
Stream.of("42")
.collect(Collectors.groupingBy(o -> toInteger(o))); // does not compile
通常,您需要像以前一样尝试捕获异常,但是有一个解决方法:
@Test
public void example_1() throws Exception {
Stream.of("42")
.collect(Collectors.groupingBy(unchecked(this::toInteger)));
}
public Integer toInteger(String string) throws IOException {
throw new IOException("whoopsie!");
}
private static <T, R> Function<T, R> unchecked(ThrowingFunction<T, R> f) {
return t -> {
try {
return f.apply(t);
} catch (Throwable thr) {
return ThrowingFunction.sneakyThrow(thr);
}
};
}
public interface ThrowingFunction<T, R> {
R apply(T t) throws Throwable;
@SuppressWarnings("unchecked")
static <T extends Throwable, R> R sneakyThrow(Throwable t) throws T {
throw (T) t;
}
}
@测试
public void示例_1()引发异常{
第42流(“42”)
.collect(收集器.groupingBy(未选中(this::toInteger));
}
公共整数toInteger(字符串)引发IOException{
抛出新IOException(“哇!”);
}
未选中私有静态函数(ThrowingFunction f){
返回t->{
试一试{
返回f.apply(t);
}捕获(可丢弃的thr){
返回ThrowingFunction.Skillythrow(thr);
}
};
}
公共接口功能{
R应用(T)可丢弃;
@抑制警告(“未选中”)
静态R潜行(可丢弃的t)抛出t{
投掷(T)T;
}
}
首先,您需要创建自己的函数接口来表示可以抛出异常的函数
然后,您可以创建一个实用程序方法,将选中的lambda重新打包为标准的java.util.function
。在本例中,unchecked()
最后一步是创建一个偷偷抛出异常的方法
事实上,我想我会写一篇关于这个的文章
编辑:
我写道:忘了包装你的异常-你可以利用这里的“偷偷抛出”技巧,让你欺骗编译器认为你的异常没有被检查-这利用了Java 8中引入的类型推断规则 让我们重新创建您的问题:
public Integer toInteger(String string) throws IOException {
throw new IOException("whoopsie!");
}
Stream.of("42")
.collect(Collectors.groupingBy(o -> toInteger(o))); // does not compile
通常,您需要像以前一样尝试捕获异常,但是有一个解决方法:
@Test
public void example_1() throws Exception {
Stream.of("42")
.collect(Collectors.groupingBy(unchecked(this::toInteger)));
}
public Integer toInteger(String string) throws IOException {
throw new IOException("whoopsie!");
}
private static <T, R> Function<T, R> unchecked(ThrowingFunction<T, R> f) {
return t -> {
try {
return f.apply(t);
} catch (Throwable thr) {
return ThrowingFunction.sneakyThrow(thr);
}
};
}
public interface ThrowingFunction<T, R> {
R apply(T t) throws Throwable;
@SuppressWarnings("unchecked")
static <T extends Throwable, R> R sneakyThrow(Throwable t) throws T {
throw (T) t;
}
}
@测试
public void示例_1()引发异常{
第42流(“42”)
.collect(收集器.groupingBy(未选中(this::toInteger));
}
公共整数toInteger(字符串)引发IOException{
抛出新IOException(“哇!”);
}
未选中私有静态函数(ThrowingFunction f){
返回t->{
试一试{
返回f.apply(t);
}捕获(可丢弃的thr){
返回ThrowingFunction.Skillythrow(thr);
}
};
}
公共接口功能{
R应用(T)可丢弃;
@抑制警告(“未选中”)
静态R潜行(可丢弃的t)抛出t{
投掷(T)T;
}
}
首先,您需要创建自己的函数接口来表示可能引发异常的函数。在这种情况下,throwing函数
然后,您可以创建一个实用程序方法来重新打包y