KludJe: make any type auto-closeable
Not all resources implement AutoCloseable.
The KludJe Res
type enables RAII for any type.
Use method references to define the release method:
public void consumeEvents(Source source, Result result, UnaryOperator<XMLEvent> eventProcessor) {
try (Res<XMLEventReader> reader = res(XMLEventReader::close, inputFactory.createXMLEventReader(source));
Res<XMLEventWriter> writer = res(XMLEventWriter::close, outputFactory.createXMLEventWriter(result))) {
while (reader.unwrap().hasNext()) {
XMLEvent event = reader.unwrap().nextEvent();
event = eventProcessor.apply(event);
writer.unwrap().add(event);
}
} catch (XMLStreamException e) {
throw new UncheckedXMLStreamException(e);
}
}
KludJe: make any type auto-closeable
import uk.kludje.Res;
import javax.xml.stream.*;
import javax.xml.stream.events.XMLEvent;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import java.util.function.UnaryOperator;
import static uk.kludje.Res.res;
public class XmlEventProcessor {
private final XMLInputFactory inputFactory;
private final XMLOutputFactory outputFactory;
public XmlEventProcessor(XMLInputFactory inputFactory, XMLOutputFactory outputFactory) {
this.inputFactory = inputFactory;
this.outputFactory = outputFactory;
}
public void consumeEvents(Source source, Result result, UnaryOperator<XMLEvent> eventProcessor) {
try (Res<XMLEventReader> reader = res(XMLEventReader::close, inputFactory.createXMLEventReader(source));
Res<XMLEventWriter> writer = res(XMLEventWriter::close, outputFactory.createXMLEventWriter(result))) {
while (reader.unwrap().hasNext()) {
XMLEvent event = reader.unwrap().nextEvent();
event = eventProcessor.apply(event);
writer.unwrap().add(event);
}
} catch (XMLStreamException e) {
throw new UncheckedXMLStreamException(e);
}
}
public static class UncheckedXMLStreamException extends RuntimeException {
public UncheckedXMLStreamException(XMLStreamException e) {
super(e);
}
}
}
Before:
import javax.xml.stream.*;
import javax.xml.stream.events.XMLEvent;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import java.util.function.UnaryOperator;
public class XmlEventProcessorVerbose {
private final XMLInputFactory inputFactory;
private final XMLOutputFactory outputFactory;
public XmlEventProcessorVerbose(XMLInputFactory inputFactory, XMLOutputFactory outputFactory) {
this.inputFactory = inputFactory;
this.outputFactory = outputFactory;
}
public void consumeEvents(Source source, Result result, UnaryOperator<XMLEvent> consumer) {
try {
XMLEventReader reader = inputFactory.createXMLEventReader(source);
try {
XMLEventWriter writer = outputFactory.createXMLEventWriter(result);
try {
while (reader.hasNext()) {
XMLEvent event = reader.nextEvent();
event = consumer.apply(event);
writer.add(event);
}
} finally {
writer.close();
}
} finally {
reader.close();
}
} catch (XMLStreamException e) {
throw new UncheckedXMLStreamException(e);
}
}
public static class UncheckedXMLStreamException extends RuntimeException {
public UncheckedXMLStreamException(XMLStreamException e) {
super(e);
}
}
}
KludJe: easy equals, hashCode and toString
Define significant properties a single time:
private static final Meta<Product> META = Meta.meta(Product.class)
.longs(p -> p.id)
.objects(p -> p.description)
.ints(p -> p.inventory);
@Override
public boolean equals(Object obj) {
return META.equals(this, obj);
}
@Override
public int hashCode() {
return META.hashCode(this);
}
@Override
public String toString() {
return META.toString(this);
}
KludJe: easy equals, hashCode and toString
import uk.kludje.Meta;
import static uk.kludje.Meta.meta;
public class Product {
private static final Meta<Product> META = meta(Product.class)
.longs(p -> p.id)
.objects(p -> p.description)
.ints(p -> p.inventory);
private final long id;
private final String description;
private final int inventory;
public Product(long id, String description, int inventory) {
this.id = id;
this.description = description;
this.inventory = inventory;
}
public long getId() {
return id;
}
public String getDescription() {
return description;
}
public int getInventory() {
return inventory;
}
@Override
public boolean equals(Object obj) {
return META.equals(this, obj);
}
@Override
public int hashCode() {
return META.hashCode(this);
}
@Override
public String toString() {
return META.toString(this);
}
}
Before:
public class ProductVerbose {
private final long id;
private final String description;
private final int inventory;
public ProductVerbose(long id, String description, int inventory) {
this.id = id;
this.description = description;
this.inventory = inventory;
}
public long getId() {
return id;
}
public String getDescription() {
return description;
}
public int getInventory() {
return inventory;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProductVerbose that = (ProductVerbose) o;
if (id != that.id) return false;
if (inventory != that.inventory) return false;
return description != null ? description.equals(that.description) : that.description == null;
}
@Override
public int hashCode() {
int result = (int) (id ^ (id >>> 32));
result = 31 * result + (description != null ? description.hashCode() : 0);
result = 31 * result + inventory;
return result;
}
@Override
public String toString() {
return "ProductVerbose {" +
id
+ ", "
+ description
+ ", "
+ inventory
+ '}';
}
}
KludJe: checked exceptions as unchecked
The linesIn
method declares that it throws IOException
which usually requires
it to be handled in a catch block.
The UFunction
interface allows passing exceptions up through the lambda code without catch
blocks:
public Map<Path, Long> countLines(Collection<? extends Path> paths) throws IOException {
return paths.stream()
.parallel()
.collect(toConcurrentMap(p -> p, asUFunction(this::linesIn)));
}
private long linesIn(Path path) throws IOException {
try (Stream<String> lines = Files.lines(path, UTF_8)) {
return lines.count();
}
}
As well as providing unchecked implementations standard library functional interfaces KludJe provides an annotation processor for generating your own types.
KludJe: checked exceptions as unchecked
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.nio.charset.StandardCharsets.UTF_8;
import static uk.kludje.fn.function.UFunction.asUFunction;
/**
* Line counter - stream approach with checked exception handling.
*/
public class LineCounter {
public Map<Path, Long> countLines(Collection<? extends Path> paths) throws IOException {
return paths.stream()
.parallel()
.collect(Collectors.<Path, Path, Long>toConcurrentMap(p -> p, asUFunction(this::linesIn)));
}
private long linesIn(Path path) throws IOException {
try (Stream<String> lines = Files.lines(path, UTF_8)) {
return lines.count();
}
}
}
Before:
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.nio.charset.StandardCharsets.UTF_8;
public class LineCounterVerbose {
public Map<Path, Long> countLines(Collection extends Path> paths) throws IOException {
try {
ConcurrentMap<Path, Long> result = paths.stream()
.parallel()
.collect(Collectors.<Path, Path, Long>toConcurrentMap(p -> p, this::linesIn));
return result;
} catch (UncheckedIOException e) {
throw e.getCause();
}
}
private Long linesIn(Path path) {
try (Stream<String> lines = Files.lines(path, UTF_8)) {
return lines.count();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
KludJe: reduce null check verbosity
This code avoids making explicit null checks in a deep object graph:
// import uk.kludje.Nullifier;
F f = Nullifier.eval(a, A::getB, B::getC, C::getD, D::getE, E::getF);
This replaces this kind of code:
if (a != null) {
B b = a.getB();
if (b != null) {
C c = b.getC();
etc.
KludJe: Download
Binaries are available from Maven central:
Sources (Apache 2.0 license) are available on GitHub.
KludJe
kludge n. SlangA system, especially a computer system, that is constituted of poorly matched elements or of elements originally intended for other applications.
KludJe is a Java lambda API for use with Java 8 and above.
Examples: