Java 7 introduced the AutoCloseable interface for use in try-with-resources statements. However, not every resource implements this interface. The JDK's own StAX resources don't; 3rd party types like SWT widgets or SNMP4J I/O classes may not be able to for compile-time compatibility reasons.
This post looks at releasing any resource using Java 8 lambdas.
Using method references to auto-close
Implementing
AutoCloseable
can be a one-liner:
AutoCloseable closer = reader::close
However this means the base
Exception
type needs to be dealt with:
public static void consume(XMLInputFactory factory, Source source, Consumer<XMLEvent> eventConsumer)
throws XMLStreamException {
XMLEventReader reader = factory.createXMLEventReader(source);
try (AutoCloseable closer = reader::close) {
while (reader.hasNext()) {
eventConsumer.accept(reader.nextEvent());
}
} catch (RuntimeException e) {
throw e;
} catch (XMLStreamException e) {
throw e;
} catch (Exception e) {
throw new AssertionError("Not going to happen");
}
}
Better auto-close with method references
The problem of dealing with
Exception
can be dealt with by defining a more specific interface:
public static void consume(XMLInputFactory factory, Source source, Consumer<XMLEvent> eventConsumer)
throws XMLStreamException {
XMLEventReader reader = factory.createXMLEventReader(source);
try (XMLStreamCloser closer = reader::close) {
while (reader.hasNext()) {
eventConsumer.accept(reader.nextEvent());
}
}
}
private interface XMLStreamCloser extends AutoCloseable {
void close() throws XMLStreamException;
}
However if
XMLStreamException
needs to be handled within the method you start to deal with nested try
blocks:
public static void consume(XMLInputFactory factory, Source source, Consumer<XMLEvent> eventConsumer) {
try {
XMLEventReader reader = factory.createXMLEventReader(source);
try (XMLStreamCloser closer = reader::close) {
while (reader.hasNext()) {
eventConsumer.accept(reader.nextEvent());
}
}
} catch (XMLStreamException e) {
// TODO: handle exception
}
}
private interface XMLStreamCloser extends AutoCloseable {
void close() throws XMLStreamException;
}
It gets worse when there is more than one resource:
public static void copy(XMLInputFactory inFactory, Source source, XMLOutputFactory outFactory, Result result) {
try {
XMLEventReader reader = inFactory.createXMLEventReader(source);
try (XMLStreamCloser closer = reader::close) {
XMLEventWriter writer = outFactory.createXMLEventWriter(result);
try (XMLStreamCloser writerCloser = writer::close) {
while (reader.hasNext()) {
writer.add(reader.nextEvent());
}
}
}
} catch (XMLStreamException e) {
// TODO: handle exception
}
}
private interface XMLStreamCloser extends AutoCloseable {
void close() throws XMLStreamException;
}
Auto-close any type
Lambdas and method references can be used to write more compact code at the expense of making the try statement uglier:
//import uk.kludje.Res;
//import static uk.kludje.Res.res;
public static void copy(XMLInputFactory inFactory, Source source, XMLOutputFactory outFactory, Result result) {
try (Res<XMLEventReader> reader = res(XMLEventReader::close, inFactory.createXMLEventReader(source));
Res<XMLEventWriter> writer = res(XMLEventWriter::close, outFactory.createXMLEventWriter(result))) {
while (reader.unwrap().hasNext()) {
writer.unwrap().add(reader.unwrap().nextEvent());
}
} catch (XMLStreamException e) {
// TODO: handle exception
}
}
This code leverages the KludJe Res (doc) class as an example.
Resources
See:
- Maven Central for KludJe binaries
- GitHub for KludJe sources
No comments:
Post a Comment
All comments are moderated