有一种lambdaj方式可以整齐地做到这一点吗?我知道标题听起来很复杂,但下面的代码片段应该清楚说明:
private List<String[]> getContractLineItemsForDatatables(List<ContractLineItem> contractLineItems) {
List<String[]> contractLineItemsForDatatables = Lists.newArrayList();
for (ContractLineItem contractLineItem : contractLineItems) {
contractLineItemsForDatatables.add( contractLineItem.getDataTablesRow());
}
return contractLineItemsForDatatables;
}
使用Lambdaj必须有一个简洁的方法来避免上面的for循环,但我无法理解它。 btw contractLineItem.getDatatablesRow()返回一个String []。
所以我想做的是:
对contractLineItems列表中的所有元素运行getDataTablesRow(),并将它们添加到contactLineItemsForDatatables列表中。
有什么建议吗?
答案 0 :(得分:4)
大多数冗长来自变量名称的选择,而不是Java代码。
private static List<String[]> extractDataTableRows(List<ContractLineItem> items) {
List<String[]> ret = new ArrayList<>();
for (ContractLineItem item : items) ret.add(item.getDataTablesRow());
return ret;
}
如果抛出异常,它看起来像
Exception in thread "main" java.lang.RuntimeException
at Main$ContractLineItem.getDataTablesRow(Main.java:87)
at Main.extractDataTableRows(Main.java:50)
at Main.main(Main.java:27)
使用番石榴的lambda
private static List<String[]> extractDataTableRows(List<ContractLineItem> items) {
return Lists.transform(items, new Function<ContractLineItem, String[]>() {
@Override
public String[] apply(ContractLineItem item) {
return item.getDataTablesRow();
}
});
}
如果抛出异常,它看起来像
Exception in thread "main" java.lang.RuntimeException
at Main$ContractLineItem.getDataTablesRow(Main.java:76)
at Main$1.apply(Main.java:38)
at Main$1.apply(Main.java:35)
at com.google.common.collect.Lists$TransformingRandomAccessList.get(Lists.java:495)
at java.util.AbstractList$Itr.next(AbstractList.java:358)
at java.util.AbstractCollection.toString(AbstractCollection.java:459)
at java.lang.String.valueOf(String.java:2957)
at java.io.PrintStream.println(PrintStream.java:821)
at Main.main(Main.java:31)
注意:在使用List之前不会触发异常。
这个Guava Caveat对我来说已经足够清楚了。
从Java 7开始,Java中的函数式编程只能通过匿名类的笨拙和冗长的使用来近似。预计这将在Java 8中发生变化,但Guava目前针对的是Java 5及更高版本的用户。
过度使用Guava的函数式编程习惯用法会导致冗长,混乱,难以理解和低效的代码。这些是迄今为止最容易(也是最常见)被滥用的番石榴部分,当你为了使你的代码“单线”而荒谬的长度时,番石榴团队就会哭泣。
使用Java 8.
private static List<String[]> extractDataTableRows(List<ContractLineItem> items) {
return items.stream()
.<String[]>map(ContractLineItem::getDataTablesRow)
.into(new ArrayList<>());
}
添加您可以编写的实用工具方法
public static <E, R> List<R> map(Collection<E> elements, Function<? super E, ? extends R> function) {
return elements.stream().<R>map(function).into(new ArrayList<R>());
}
// hiding the guff, this is more readable IMHO.
private static List<String[]> extractDataTableRows(List<ContractLineItem> items) {
return map(items, ContractLineItem::getDataTablesRow);
}
如果抛出异常,它可能看起来像这样
Exception in thread "main" java.lang.RuntimeException
at Main$ContractLineItem.getDataTablesRow(Main.java:77)
at Main$$Lambda$1.apply(Unknown Source)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:87)
at java.util.Arrays$ArraySpliterator.forEach(Arrays.java:4551)
at java.util.stream.AbstractPipeline$PipelineHelperImpl.into(AbstractPipeline.java:197)
at java.util.stream.op.ForEachOp.evaluateSequential(ForEachOp.java:86)
at java.util.stream.op.ForEachOp.evaluateSequential(ForEachOp.java:37)
at java.util.stream.AbstractPipeline.pipeline(AbstractPipeline.java:336)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:142)
at java.util.Collection.addAll(Collection.java:505)
at java.util.ArrayList.addAll(ArrayList.java)
at java.util.stream.ReferencePipeline.into(ReferencePipeline.java:189)
at Main.map(Main.java:34)
at Main.extractDataTableRows(Main.java:39)
at Main.main(Main.java:29)
虽然@ Edwin的答案是最短的,但它是最难调试和维护的,因为有很多“魔法”正在实现这一点。这适用于单元测试,但您不希望它出现在生产代码IMHO中。
Exception in thread "main" ch.lambdaj.function.argument.InvocationException: Failed invocation of public java.lang.String[] Main$ContractLineItem.getDataTablesRow() on object Main$ContractLineItem@1d724f31 caused by: null
at ch.lambdaj.function.argument.Invocation.invokeOn(Invocation.java:70)
at ch.lambdaj.function.argument.InvocationSequence.invokeOn(InvocationSequence.java:91)
at ch.lambdaj.function.argument.InvocationSequence.invokeOn(InvocationSequence.java:85)
at ch.lambdaj.function.argument.Argument.evaluate(Argument.java:35)
at ch.lambdaj.function.convert.ArgumentConverter.convert(ArgumentConverter.java:36)
at ch.lambdaj.function.convert.ConverterIterator.next(ConverterIterator.java:37)
at ch.lambdaj.Lambda.convert(Lambda.java:986)
at ch.lambdaj.Lambda.extract(Lambda.java:1035)
at Main.extractDataTableRows(Main.java:49)
at Main.main(Main.java:27)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:474)
at ch.lambdaj.function.argument.Invocation.invokeOn(Invocation.java:68)
... 14 more
Caused by: java.lang.RuntimeException
at Main$ContractLineItem.getDataTablesRow(Main.java:85)
... 19 more
这种语法需要一些使用,但我想,当他们收紧语法并删除一些样板代码时,它可能更具可读性。
以下是一个很好的比较Java 8 Lambda vs LambdaJ vs Guava vs Iterative approach原文为俄文,请原谅Google翻译;)
答案 1 :(得分:2)
怎么样
List<String[]> items = extract(contractLineItems, on(ContractLineItem.class).getDataTablesRow());
LambaJ附带一个名为extract的方法,它是一个映射器。您还可以阅读有关converting objects with lambdaj的参考资料。