【问题标题】:Lambda nested stream Filter by Method with ExceptionLambda嵌套流按异常方法过滤
【发布时间】:2017-11-04 04:50:05
【问题描述】:

我回答了这个question

这是代码:

import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

方法!

private String[] getHostAddresses() {
  Set<String> HostAddresses = new HashSet<>();
  try {
    for (NetworkInterface ni : Collections.list(NetworkInterface.getNetworkInterfaces())) {
      if (!ni.isLoopback() && ni.isUp() && ni.getHardwareAddress() != null) {
        for (InterfaceAddress ia : ni.getInterfaceAddresses()) {
          if (ia.getBroadcast() != null) {  //If limited to IPV4
            HostAddresses.add(ia.getAddress().getHostAddress());
          }
        }
      }
    }
  } catch (SocketException e) { }
  return HostAddresses.toArray(new String[0]);
}

现在我想使用基于 Java 8 的 Lamba Stream 进行翻译。 这是我的代码:

try {

  Collections.list(NetworkInterface.getNetworkInterfaces())
      .stream()
      .filter(ni -> !ni.isLoopback())  //unreported exception SocketException; must be caught or declared to be thrown
      .filter(ni -> ni.isUp())  //unreported exception SocketException; must be caught or declared to be thrown
      .filter(ni -> ni.getHardwareAddress() != null)  //unreported exception SocketException; must be caught or declared to be thrown
      .flatMap(ni -> ni.getInterfaceAddresses().stream())
      .filter(ia -> ia.getBroadcast() != null)
      .forEach(ia -> HostAddresses.add(ia.getAddress().getHostAddress()));

} catch (SocketException e) {
  System.out.println(e.getMessage());
}

但是当我改用 Try catch...

    try {
      Collections.list(NetworkInterface.getNetworkInterfaces())
          .stream()
          .filter(ni -> {  //incompatible types: bad return type in lambda expression missing return value
            try {
              !ni.isLoopback(); //not a statement cannot find symbol symbol:   method isLoopback() location: variable ni of type T where T is a type-variable: T extends Object declared in interface Stream
            } catch (SocketException ex) {  //exception SocketException is never thrown in body of corresponding try statement
              Logger.getLogger(JPanelServerClient.class.getName()).log(Level.SEVERE, null, ex);
            }
          })
          .filter(ni -> ni.isUp())
          .filter(ni -> ni.getHardwareAddress() != null)
          .flatMap(ni -> ni.getInterfaceAddresses().stream())
          .filter(ia -> ia.getBroadcast() != null)
          .forEach(ia -> HostAddresses.add(ia.getAddress().getHostAddress()));

    } catch (SocketException e) {
      System.out.println(e.getMessage());
    }

根据提示@Jacob-G,这解决了问题(但他有理由说“并非一切都必须正常运行”)

try {
  Collections.list(NetworkInterface.getNetworkInterfaces())
  .stream()
  .filter(ni -> {
    try {
      return !ni.isLoopback();
    } catch (SocketException ex) {
      System.out.println(ex.getMessage());
      return false;
    }
  })
  .filter(ni -> {
    try {
      return ni.isUp();
    } catch (SocketException ex) {
      System.out.println(ex.getMessage());
      return false;
    }
  })
  .filter(ni -> {
    try {
      return ni.getHardwareAddress() != null;
    } catch (SocketException ex) {
      System.out.println(ex.getMessage());
      return false;
    }
  })
  .flatMap(ni -> ni.getInterfaceAddresses().stream())
  .filter(ia -> ia.getBroadcast() != null)
  .forEach(ia -> HostAddresses.add(ia.getAddress().getHostAddress()));
} catch (SocketException e) {
  System.out.println(e.getMessage());
}

我如何翻译它(更简单)? 如何翻译?

【问题讨论】:

  • 并非所有东西都必须正常运行。要解决上一个示例的问题,请将!ni.isLoopback(); 更改为return !ni.isLoopback();,因为Predicate 必须返回boolean。不过,您还需要在异常中返回一个值,或者抛出一个异常。
  • 为了使代码更接近函数式代码,您还可以将带有异常的方法包装在辅助函数中,然后在代码的功能部分中直接使用辅助函数。

标签: java lambda exception-handling stream nested


【解决方案1】:

不幸的是,在 java 流中处理检查的异常是丑陋的。 您必须创建一个单独的函数,该函数采用谓词(过滤操作)捕获任何已检查的异常,并将其作为运行时异常重新抛出

由于我缺乏想象力,请考虑以下两个您无法控制的功能(想想库或 jdk 的一部分):

boolean isEven(int i) throws IOException {
    return i % 2 == 0;
}

boolean isOdd(int i) throws IOException {
    return i % 2 == 1;
}

Stream.of(1, 2, 3, 4, 5)
        .filter(i -> isEven(i))// compilation error
        .filter(i -> isOdd(i))// compilation error
        .collect(Collectors.toList());

方法一:为两个函数中的每一个编写一个包装器方法并在那里处理异常:

boolean isEvenWrapper(int i){
  try{
    return isEven(i);
   } catch (IOException ex){
     throw new UnCheckedIOException(ex);
}

然后你的流看起来像:

Stream.of(1, 2, 3, 4, 5)
        .filter(i -> isEvenWrapper(i)) 
        .filter(i -> isOddWrapper(i))          //compiles and runs.
        .collect(Collectors.toList());

方法 2:如果我们有 1 或 2 个过滤器函数,方法 1 很容易,但如果我们有更多过滤器函数,为每个可抛出方法编写包装器函数变得乏味。

我们需要为抛出异常的谓词创建一个函数式接口。

@FunctionalInterface
public interface CheckedPredicate<T> {
    boolean test(T t) throws Throwable;
}

另一个 Predicate 或方法接受这个 CheckedPredicate 并安全地评估它。

public static <T> Predicate<T> uncheckedPredicate(CheckedPredicate<T> predicate) {
    return t -> {
        try {
            return predicate.test(t);
        } catch (Throwable x) {
            throw new RuntimeException(x);
        }
    };
}

现在我们的流变成了,

Stream.of(1, 2, 3, 4, 5)
        .filter(uncheckedPredicate(i -> isEven(i)))
        .filter(uncheckedPredicate(i -> isOdd(i)))  //compiles and runs.
        .collect(Collectors.toList());

我所描述的方法 2 功能由JOOL 提供 特别是这个类Unchecked

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多