Java 8流:简写为myList.stream().map(Foo::bar).collect(Collectors.toList())

huangapple go评论75阅读模式
英文:

Java 8 streams: Shorthand for myList.stream().map(Foo::bar).collect(Collectors.toList())

问题

以下是翻译好的内容:

有没有一种常见的缩写形式来表示以下内容?欢迎使用外部依赖,比如Guava。

myList.stream().map(Foo::bar).collect(Collectors.toList());

如果我必须要实现它,会是类似这样的:

static <T, U> List<U> mapApply(List<T> list, Function<T, U> function) {
    return list.stream().map(function).collect(Collectors.toList());
}

是否存在一种适用于任何可迭代对象(Iterable)的方法?如果没有,我该如何编写一个?我开始像这样思考:

static <T, U, V extends Iterable<T>> V<U> mapApply(V<T> iterable, Function<T, U> function) {
    return iterable.stream().map(function).collect(???);
}
英文:

Is there a common shorthand for the following? External dependencies like Guava welcome.

myList.stream().map(Foo::bar).collect(Collectors.toList());

If I had to implement it, it'd be something like:

static &lt;T, U&gt; List&lt;U&gt; mapApply(List&lt;T&gt; list, Function&lt;T, U&gt; function) {
    return list.stream().map(function).collect(Collectors.toList());
}

Is there one that works for any Iterable? If not, how would I write one? I started thinking about it like this:

static &lt;T, U, V extends Iterable&gt; V&lt;U&gt; mapApply(V&lt;T&gt; iterable, Function&lt;T, U&gt; function) {
    return iterable.stream().map(function).collect(???);
}

答案1

得分: 7

在情况下,`Foo::bar` 返回一个 `Foo` 的实例,也就是说,你需要将 `T` 再次转换为 `T`,那么你可以使用 [`List::replaceAll`][1],它使用 `UnaryOperator&lt;T&gt;`,因此每个项目都被同一类型的项目替换。这个解决方案会改变原始列表。

    List&lt;String&gt; list = Arrays.asList(&quot;John&quot;, &quot;Mark&quot;, &quot;Pepe&quot;);
    list.replaceAll(s -&gt; &quot;hello &quot; + s);

如果你想将 `T` 转换为 `R`,你唯一能做的就是要么使用你当前的解决方案,进行 `stream()` -&gt; `map()` -&gt; `collect()` 方法的调用序列,要么使用一个简单的迭代。

一个包装了这个方法的静态方法也会达到相同的效果。请注意,你不能使用相同的方式从 `Collection` 和 `Iterable` 创建一个 `Stream`。你也可以传递自定义的 `Collector`。

 - `T` 是输入的 `Collection` 或 `Iterable` 的通用类型。
 - `R` 是映射函数结果的通用类型(从 `T` 到 `R` 的映射)

**从 `Collection&lt;T&gt;`**:

```java
List&lt;Bar&gt; listBarFromCollection = mapApply(collectionFoo, Foo::bar, Collectors.toList());
static &lt;T, R&gt; List&lt;R&gt; mapApply(Collection&lt;T&gt; collection, Function&lt;T, R&gt; function) {
    return collection.stream()
        .map(function)
        .collect(Collectors.toList());
}

Iterable&lt;T&gt;

List&lt;Bar&gt; listBarFromIterable = mapApply(iterableFoo, Foo::bar, Collectors.toList());
static &lt;T, R&gt; List&lt;R&gt; mapApply(Iterable&lt;T&gt; iterable, Function&lt;T, R&gt; function) {
    return StreamSupport.stream(iterable.spliterator(), false)
        .map(function)
        .collect(Collectors.toList());
}

... 使用一个 Collector:

如果你想传递一个自定义的 Collector,它将是 Collector&lt;R, ?, U&gt;,而方法的返回类型将是 U,而不是 List&lt;R&gt;。正如 @Holger 指出的,将 Collector 传递给方法与调用实际的 stream() -> map() -> collect() 没有太大区别。


<details>
<summary>英文:</summary>

In the case `Foo::bar` returns an instance of `Foo` again, ie. you need to transform `T` into `T` again, then you can use [`List::replaceAll`][1] which uses `UnaryOperator&lt;T&gt;`, therefore each item is replaced by one of a same type. This solution mutates the original list.

    List&lt;String&gt; list = Arrays.asList(&quot;John&quot;, &quot;Mark&quot;, &quot;Pepe&quot;);
    list.replaceAll(s -&gt; &quot;hello &quot; + s);

If you want to transform `T` into `R`, all you can do is to either use your current solution with a sequence of `stream()` -&gt; `map()` -&gt; `collect()` method calls  or a simple iteration.

A static method wrapping this would do the same as well. Note that you cannot create a `Stream` from both `Collection` and `Iterable` using the same way. Feel free to pass also your custom `Collector`.

 - `T` is a generic type of an input `Collection` or `Iterable`.
 - `R` is a generic type of the mapping function result (mapping from `T` to `R`)

**From `Collection&lt;T&gt;`**

List<Bar> listBarFromCollection = mapApply(collectionFoo, Foo::bar, Collectors.toList());

static <T, R> List<R> mapApply(Collection<T> collection, Function<T, R> function) {
return collection.stream()
.map(function)
.collect(Collectors.toList());
}


**From `Iterable&lt;T&gt;`**

List<Bar> listBarFromIterable = mapApply(iterableFoo, Foo::bar, Collectors.toList());

static <T, R> List<R> mapApply(Iterable<T> iterable, Function<T, R> function) {
return StreamSupport.stream(iterable.spliterator(), false)
.map(function)
.collect(Collectors.toList());
}


_____

**... with a `Collector`**:

If you want to pass a custom `Collector`, it would be `Collector&lt;R, ?, U&gt; collector` and the return type of the method `U` instead of `List&lt;R&gt;`. As @Holger pointed out, passing a `Collector` to a method would not much differ from calling an actual `stream()` -&gt; `map()` -&gt; `collect()`.

  [1]: https://docs.oracle.com/javase/8/docs/api/java/util/List.html#replaceAll-java.util.function.UnaryOperator-

</details>



# 答案2
**得分**: 1

你可以这样实现这个方法:

```java
public class StreamShorthandUtil {
    
    public static <T, U, V extends Collection<T>, W> W mapApply(V in, Function<T, U> function, Collector<U, ?, W> collector) {
        return in.stream().map(function).collect(collector);
    }

    // 用于测试的主类
    public static void main(String[] args) {
        List<String> numbersAsString = Arrays.asList("1", "2", "3", "4", "5");
        List<Integer> numbers = mapApply(numbersAsString, Integer::parseInt, Collectors.toList());
    }
}

这个方法有一个 Collector 参数,用于定义返回的类型,除了输入和映射函数。

英文:

You could implement the method like this:

public class StreamShorthandUtil {
	
	public static &lt;T, U, V extends Collection&lt;T&gt;, W&gt; W mapApply(V in, Function&lt;T, U&gt; function, Collector&lt;U, ?, W&gt; collector) {
		return in.stream().map(function).collect(collector);
	}

    // main class for testing
	public static void main(String[] args) {
		List&lt;String&gt; numbersAsString = Arrays.asList(&quot;1&quot;, &quot;2&quot;, &quot;3&quot;, &quot;4&quot;, &quot;5&quot;);
		List&lt;Integer&gt; numbers = mapApply(numbersAsString, Integer::parseInt, Collectors.toList());
	}
}

This method has a Collector paramter, to define the returned type, in addition to the input and mapper functions.

答案3

得分: 1

你可以使用Eclipse Collections,它在集合上拥有丰富的 API,并且对于诸如 collect(也称为 map)之类的方法具有协变返回类型。

例如:

MutableList<Foo> fooList;
MutableList<Bar> barList = fooList.collect(Foo::bar);

MutableSet<Foo> fooSet;
MutableSet<Bar> barSet = fooSet.collect(Foo::bar);

MutableBag<Foo> fooBag;
MutableBag<Bar> barBag = fooBag.collect(Foo::bar);

Iterate 实用类还适用于任何 Iterable,并提供了丰富的协议集合。

Iterable<Foo> fooIterable;
List<Bar> barList = Iterate.collect(fooIterable, Foo::bar, new ArrayList<>());
Set<Bar> barSet = Iterate.collect(fooIterable, Foo::bar, new HashSet<>());

注意:我是 Eclipse Collections 的贡献者。

英文:

You could use Eclipse Collections which has a rich API directly on collections with covariant return types for methods like collect (aka map).

For example:

MutableList&lt;Foo&gt; fooList;
MutableList&lt;Bar&gt; barList = fooList.collect(Foo::bar);

MutableSet&lt;Foo&gt; fooSet;
MutableSet&lt;Bar&gt; barSet = fooSet.collect(Foo::bar);

MutableBag&lt;Foo&gt; fooBag;
MutableBag&lt;Bar&gt; barBag = fooBag.collect(Foo::bar);

The Iterate utility class will also work with any Iterable and provides a rich set of protocols.

Iterable&lt;Foo&gt; fooIterable;
List&lt;Bar&gt; barList = Iterate.collect(fooIterable, Foo::bar, new ArrayList&lt;&gt;());
Set&lt;Bar&gt; barSet = Iterate.collect(fooIterable, Foo::bar, new HashSet&lt;&gt;());

Note: I am a committer for Eclipse Collections.

huangapple
  • 本文由 发表于 2020年8月26日 23:06:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/63600503.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定