英文:
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 <T, U> List<U> mapApply(List<T> list, Function<T, U> 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 <T, U, V extends Iterable> V<U> mapApply(V<T> iterable, Function<T, U> function) {
return iterable.stream().map(function).collect(???);
}
答案1
得分: 7
在情况下,`Foo::bar` 返回一个 `Foo` 的实例,也就是说,你需要将 `T` 再次转换为 `T`,那么你可以使用 [`List::replaceAll`][1],它使用 `UnaryOperator<T>`,因此每个项目都被同一类型的项目替换。这个解决方案会改变原始列表。
List<String> list = Arrays.asList("John", "Mark", "Pepe");
list.replaceAll(s -> "hello " + s);
如果你想将 `T` 转换为 `R`,你唯一能做的就是要么使用你当前的解决方案,进行 `stream()` -> `map()` -> `collect()` 方法的调用序列,要么使用一个简单的迭代。
一个包装了这个方法的静态方法也会达到相同的效果。请注意,你不能使用相同的方式从 `Collection` 和 `Iterable` 创建一个 `Stream`。你也可以传递自定义的 `Collector`。
- `T` 是输入的 `Collection` 或 `Iterable` 的通用类型。
- `R` 是映射函数结果的通用类型(从 `T` 到 `R` 的映射)
**从 `Collection<T>`**:
```java
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());
}
从 Iterable<T>
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());
}
... 使用一个 Collector
:
如果你想传递一个自定义的 Collector
,它将是 Collector<R, ?, U>
,而方法的返回类型将是 U
,而不是 List<R>
。正如 @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<T>`, therefore each item is replaced by one of a same type. This solution mutates the original list.
List<String> list = Arrays.asList("John", "Mark", "Pepe");
list.replaceAll(s -> "hello " + 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()` -> `map()` -> `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<T>`**
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<T>`**
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<R, ?, U> collector` and the return type of the method `U` instead of `List<R>`. As @Holger pointed out, passing a `Collector` to a method would not much differ from calling an actual `stream()` -> `map()` -> `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 <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);
}
// main class for testing
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());
}
}
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<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);
The Iterate
utility class will also work with any Iterable
and provides a rich set of protocols.
Iterable<Foo> fooIterable;
List<Bar> barList = Iterate.collect(fooIterable, Foo::bar, new ArrayList<>());
Set<Bar> barSet = Iterate.collect(fooIterable, Foo::bar, new HashSet<>());
Note: I am a committer for Eclipse Collections.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论