简体   繁体   English

对于未实现 AutoCloseable 的类,使用 lambda 是否是一种安全、正确且等效的解决方法?

[英]Is using a lambda a safe, correct, and equivalent workaround for classes that do not implement AutoCloseable?

Background: I use the Java class InitialDirContext to access LDAP directories.背景:我使用 Java class InitialDirContext来访问 LDAP 目录。 Unfortunately , it does not implement interface AutoCloseable , so it cannot be used in try-with-resources blocks.不幸的是,它没有实现接口AutoCloseable ,因此不能在try-with-resources块中使用。

Here is the original code I wrote: ( inspired by this answer )这是我写的原始代码:(受这个答案的启发

final Properties props = new Properties();
// Populate 'props' here.
final InitialDirContext context = new InitialDirContext(props);
Exception e0 = null;
try {
    // use 'context' here
}
catch (Exception e) {
    // Only save a reference to the exception.
    e0 = e;
    // Why re-throw?
    // If finally block does not throw, this exception must be thrown.
    throw e;
}
finally {
    try {
        context.close();
    }
    catch (Exception e2) {
        if (null != e0) {
            e0.addSuppressed(e2);
            // No need to re-throw 'e0' here.  It was (re-)thrown above.
        }
        else {
            throw e2;
        }
    }
}

Is this a safe, correct, and equivalent replacement?这是一个安全、正确和等效的替代品吗?

try (final AutoCloseable dummy = () -> context.close()) {
    // use 'context' here
}

I think the answer is yes, but I want to confirm.认为答案是肯定的,但我想确认一下。 I tried Googling for this pattern, but I found nothing.我尝试用谷歌搜索这种模式,但我什么也没找到。 It is so simple, Thus.如此简单,如此。 I am suspicious it may not be correct.我怀疑它可能不正确。

Edit: I just found this answer with a similar pattern.编辑:我刚刚发现这个答案有类似的模式。

As explained in the other answer you linked to, it is not strictly equivalent because you have to either catch or throw Exception from AutoCloseable.close() and you must be sure not to do anything with context after the try block because it is not out of scope as if InitialDirContext directly implemented AutoCloseable .正如您链接到的另一个答案中所解释的那样,它不是严格等效的,因为您必须从AutoCloseable.close()捕获或抛出Exception ,并且您必须确保在try块之后不要对context做任何事情,因为它没有退出scope 的好像InitialDirContext直接实现了AutoCloseable Still I agree with others that this workaround is quite nice.我仍然同意其他人的观点,这种解决方法非常好。

Of course, you could also extend InitialDirContext and make it implement AutoCloseable directly or (for final classes) use a delegator pattern and wrap the target object.当然,您也可以扩展InitialDirContext并使其直接实现AutoCloseable或(对于最终类)使用委托模式并包装目标 object。

package de.scrum_master.stackoverflow;

import javax.naming.NamingException;
import javax.naming.directory.InitialDirContext;
import java.util.Hashtable;
import java.util.Properties;

public class TryWithResourcesAutoCloseableWrapper {

  public static void main(String[] args) throws NamingException {
    final Properties props = new Properties();
    props.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
    variant1(props);
    variant2(props);
    variant3(props);
  }

  public static void variant1(Properties props) throws NamingException {
    final InitialDirContext context = new InitialDirContext(props);
    try (final AutoCloseable dummy = context::close) {
      lookupMX(context);
    }
    catch (NamingException ne) {
      throw ne;
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }

  public static void variant2(Properties props) throws NamingException {
    final InitialDirContext context = new InitialDirContext(props);
    try (final MyCloseable dummy = context::close) {
      lookupMX(context);
    }
  }

  public static void variant3(Properties props) throws NamingException {
    try (final MyInitialDirContext context = new MyInitialDirContext(props)) {
      lookupMX(context);
    }
  }

  private static void lookupMX(InitialDirContext context) throws NamingException {
    System.out.println(context.getAttributes("scrum-master.de", new String[] { "MX" }));
  }

  public interface MyCloseable extends AutoCloseable {
    void close() throws NamingException;
  }

  public static class MyInitialDirContext extends InitialDirContext implements AutoCloseable {
    public MyInitialDirContext(Hashtable<?, ?> environment) throws NamingException {
      super(environment);
    }
  }

}

A few more thoughts about how to use these workarounds:关于如何使用这些解决方法的更多想法:

  • Both variant1 and variant2 come at the cost of dummy objects which inside the try block you will never use, unless you cast them to InitialDirContext first.变体 1 和variant2都以在try块中永远不会使用的dummy对象为代价,除非您首先将它们InitialDirContext variant1 Instead, you could directly use the outer context objects, of course, which is also what you suggested.相反,您当然可以直接使用外部context对象,这也是您的建议。
  • In variant3 the auto-closable context object directly has the correct (sub-)type, so you can actually work with it seamlessly without casting or dummy object.variant3中,自动关闭context object 直接具有正确的(子)类型,因此您实际上可以无缝地使用它,而无需强制转换或虚拟 object。 This comes at the cost of a special subclass.这是以特殊子类为代价的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM