迭代非列表的最短方法?

2022-09-01 04:21:10

假设我有 3 个要关闭的扫描程序实例。

我可以做

sc.close()

对于每个扫描仪。

或者我可以做这样的事情

for (Scanner sc: new Scanner[]{sc1,sc2,sc3}) {
    sc.close();
}

有没有更短的方法来做到这一点与Java 8?

类似的东西?

{sc1,sc2,sc3}.forEach((sc) -> sc.close());

答案 1

从Java 7开始,您应该使用试用资源

try(Scanner sc1 = new Scanner(""); 
    Scanner sc2 = new Scanner(""); 
    Scanner sc3 = new Scanner("")){

}
//all scanners get closed implicitly

因此,您根本不需要任何代码。

所有 for-each 或流构造的问题在于,从理论上讲,如果第一个在调用基础源的方法时失败并出现异常,则以下扫描程序不会关闭。该实现捕获任何 IOException,但没有可能发生的其他异常。close()close()Scanner.close()

使用资源进行试验的构造处理这一点,循环不处理。


编辑:虽然您的问题针对的是更通用的方法,但上述解决方案是对您的特定问题的回应:处理资源,在任何情况下都应与资源试验构造一起使用,根本不需要对关闭方法进行特殊处理(=您的特定问题的最短解决方案)。AutoCloseable

关于处理任意项目(没有资源)的更一般的问题,Java至少有两个选项:

从数组/Varargs 创建列表并对其进行迭代

for(YourItemType item : Arrays.asList(your,items,here)) {
  //do something
}

从数组/Varargs 创建流并对其应用函数

Stream.of(your,items,here).forEach(item -> { doSomething});

当然,“doSomething”可以用方法参考来代替。

Stream.of(your,items,here).forEach(this::myMethod);
...
void myMethod(YourItemType item){
  //doSomething
} 

这种方法的问题在于,必须在 lambda 表达式中显式处理已检查的异常。让我们以上面的例子为例,并抛出一个已检查的异常myMethod

void myMethod(YourItemType item) throws Exception

在这种情况下,您的流语句必须看起来像

Stream.of(your,items,here).forEach(item -> {
  try {
    myMethod(item);
  } catch (Exception e){
    //omit or throw new RuntimeException(e);
  };

这看起来不太好。但是我们可以将 lambda 主体放在一个单独的方法中

void myMethodQuietly(YourItemType item) {
  try {
    myMethod(item);
  }catch(Exception e){
    //omit or throw new RuntimeException(e);
  }
}

Stream.of(your,items,here).forEach(this::myMethodQuietly);

此方法可能对您的特定资源问题感兴趣。我们可以把所有这些放到一个把类外创建的资源都放在一个中,所有这些资源都应该在调用CompositeAutoCloseableclose()

public class CompositeAutoCloseable implements AutoCloseable {

  private List<Closeable> resources;

  public CompositeAutoCloseable(Closeable... resources) {
    this.resources = Arrays.asList(resources);
    //you could use a stream here too
  }

  @Override
  public void close() {
      this.resources.stream().forEach(this::closeQuietly);
  }

  void closeQuietly(Closeable res) {
    if(res == null)  {
        return;
    }
    try {
        res.close();
    }catch(Exception e){
        //omit
    }
  } 
}

一旦你有了这样一个帮助程序类,你就可以再次使用它来尝试使用资源。

try(CompositeAutoCloseable cac = new CompositeAutoCloseable(sc1,sc2,sc3)) {
  //do something
}

我由您来决定与初始解决方案相比,这是否有意义;)


答案 2

如果实例化与处置分离,请使用Guava的com.google.common.io.Closer


推荐