java - 将对集合中的元素运行方法的所有结果添加到另一个集合

标签 java collections closures guava lambdaj

有没有 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 循环,但我无法理解它。顺便说一句,contractLineItem.getDatatablesRow() 返回一个 String[]。

所以我想做的是:

对contractLineItems列表中的所有元素运行getDataTablesRow(),并将它们添加到contactLineItemsForDatatables列表中。

有什么建议吗?

最佳答案

大部分冗长的内容来自于变量名的选择,而不是 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)

使用 Guava 的 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对我来说已经很清楚了。

As of Java 7, functional programming in Java can only be approximated through awkward and verbose use of anonymous classes. This is expected to change in Java 8, but Guava is currently aimed at users of Java 5 and above.

Excessive use of Guava's functional programming idioms can lead to verbose, confusing, unreadable, and inefficient code. These are by far the most easily (and most commonly) abused parts of Guava, and when you go to preposterous lengths to make your code "a one-liner," the Guava team weeps.

使用 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的答案最短,但它是最难调试和维护的,因为要实现这一点需要分配“魔法”。这对于单元测试来说很好,但恕我直言,您不希望它出现在生产代码中。

 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原文为俄语,请原谅谷歌翻译;)

关于java - 将对集合中的元素运行方法的所有结果添加到另一个集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14234546/

相关文章:

python - 警告带有自由变量的每个(嵌套)函数(递归)

rust - 更高等级的生命周期和泛型表现不佳

用于替换通过 B 值链接的两个映射 Map<A,B>, Map<B,C> 的 Java 数据结构

java - 有没有办法重命名用 lombok 生成的 getter 方法?

java - 映射以下数据的键值对?

对象 : what alias should have "this" for passing into anonymous function? 内的 JavaScript 闭包

java - 使用浏览器打开多个链接有延迟

java - 运行应用程序时更新 JavaFX 控件

c# - 如何使用静态 List<T> 作为缓存对象?

php - Laravel Collection 从嵌套数据结构中获取唯一值