2017-09-17 27 views
1

我已经看到了一些与此相关的问题,但我需要一个明确的答案。我的确了解了lamba表达式运行的环境以及副作用的概念,但我相信我没有在这里看到一种解决方法。Java 8流。抛出lamba表达式中客户端方法的异常

我需要根据他们的性别来映射角色列表,但是我用来确定他们性别的方法会返回一个检查过的异常,而Collectors.groupingBy根本就不喜欢这个异常。

摆脱检查的异常不是一个选项,我需要将它发送给调用我的代码片段的客户端方法。我有什么可以做的吗?

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 { 
} 

感谢您的任何想法!

+0

我发现[这个问题](https://stackoverflow.com/questions/27644361/how-can-i-throw-checked-exceptions-from-inside-java -8流),其评论和回答非常有趣。 Tl; dr:你必须处理这个例外情况,但正如下面的答案和链接问题所显示的那样,你可以用某些模式或utils来解决它,甚至可以隐藏这些模式。 –

回答

3

解决方法可能是将未检查的异常包装在您的已检查的异常中,并从catch块中抛出后者。请注意,我们正在保存一个MException作为能够进一步工作的原因。

try { 
    return getSex(persona.getSSN()); 
} catch (MException e) { 
    throw new IllegalArgumentException(e); // choose a suitable runtime one 
} 

另一种方式去(而一个前一个修改,我不喜欢)将被写入一个Collectors.groupingBy - 友好方法前述逻辑进入:

private String getSexFriendly(String ssn) { 
    try { 
     return getSex(ssn); 
    } catch (MException e) { 
     throw new IllegalArgumentException(e); 
    } 
} 

虽然,我们将有一个好看的λ:

persona -> getSexFriendly(persona.getSSN()) 
1

忘掉包装你的异常 - 您可以利用“偷偷摸摸抛出黑客在这里,使您能够欺骗编译器认为日在不检查你的异常 - 这利用了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 

通常情况下,你需要try-catch就像你一样的例外,但有一个解决方法:首先,您需要创建自己的函数接口来表示可以抛出异常的函数。在这种情况下,ThrowingFunction

然后,您可以创建一个实用程序方法,将您检查的lambda重新打包为标准java.util.function。在这种情况下,unchecked()

最后一步是创建一个方法,偷偷地抛出一个异常。在这种情况下,sneakyThrow()

其实我想我会写一篇关于这方面的文章。

编辑: 我写道:http://4comprehension.com/sneakily-throwing-exceptions-in-lambda-expressions-in-java/

+0

不要忘了在这里留下文章的链接+1 :) – Andrew

+0

@AndrewTobilko谢谢你的提醒:) –

相关问题