迭代非列表的最短方式?

E. *_*din 37 java java-8

假设我有3个扫描程序实例,我想关闭它.

我可以

sc.close()
Run Code Online (Sandbox Code Playgroud)

对于每个扫描仪.

或者我可以做类似的事情

for (Scanner sc: new Scanner[]{sc1,sc2,sc3}) {
    sc.close();
}
Run Code Online (Sandbox Code Playgroud)

使用Java 8有没有更短的方法?

类似的东西?

{sc1,sc2,sc3}.forEach((sc) -> sc.close());
Run Code Online (Sandbox Code Playgroud)

Ger*_*cke 73

从Java 7开始,您应该使用try-with-resources

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

}
//all scanners get closed implicitly
Run Code Online (Sandbox Code Playgroud)

所以你根本不需要任何代码.

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

try-with-resources构造处理它,循环不处理.


编辑:虽然你的问题针对更一般的方法,但上述解决方案是对你的特定问题的回应:处理AutoCloseable资源,在任何情况下都应该与资源试用结构一起使用,不需要特殊处理完全关闭方法(=对您的特定问题的最短解决方案).

关于处理任意项(不是资源)的更普遍的问题,Java至少有两个选择:

从Array/Varargs创建一个List并迭代它

for(YourItemType item : Arrays.asList(your,items,here)) {
  //do something
}
Run Code Online (Sandbox Code Playgroud)

从Array/Varargs创建流并将函数应用于它

Stream.of(your,items,here).forEach(item -> { doSomething});
Run Code Online (Sandbox Code Playgroud)

当然,"doSomething"可以用方法参考替换

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

该方法的问题是,必须在lambda表达式中显式处理已检查的异常.让我们拿上面的例子,myMethod抛出一个检查过的异常

void myMethod(YourItemType item) throws Exception
Run Code Online (Sandbox Code Playgroud)

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

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

这看起来不太好.但我们可以将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);
Run Code Online (Sandbox Code Playgroud)

您的特定资源问题可能会对此方法感兴趣.我们可以将所有这些放入一个CompositeAutoCloseable需要在类外部创建的资源,所有资源都应该在调用时安全地关闭close()

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
    }
  } 
}
Run Code Online (Sandbox Code Playgroud)

一旦你有这样一个帮助类,你可以再次使用try-with-resources.

try(CompositeAutoCloseable cac = new CompositeAutoCloseable(sc1,sc2,sc3)) {
  //do something
}
Run Code Online (Sandbox Code Playgroud)

我把它留给你来决定与初始解决方案相比这是否合理;)

  • @Benjamin Gruenbaum:该帖子使用了许多Java中不存在的C#构造.通常,使用*`Scanner`来修复"Scanner"类的构造函数中的潜在错误并不是代码的责任.当然,它不是"100%安全",但没有.你如何防止有人拔插头? (6认同)