Java 9 Collectors.flatMapping rewritten in Java 8
I got in touch with a new feature since java-9 called Collectors.flatMapping
that takes place as a downstream of grouping or partitioning. Such as (example taken from here):
List<List<Integer>> list = Arrays.asList(
Arrays.asList(1, 2, 3, 4, 5, 6),
Arrays.asList(7, 8, 9, 10));
Map<Integer, List<Integer>> map =list.stream()
.collect(Collectors.groupingBy(
Collection::size,
Collectors.flatMapping(
l -> l.stream().filter(i -> i % 2 == 0),
Collectors.toList())));
{4=[8, 10], 6=[2, 4, 6]}
This is a fairly elegant way using just 3 collectors. I need to rewrite the collector in java-8 where is not yet supported. My attempt use 6 Collectors that is quite an extensive usage and I am not able to figure out a way using less of them:
Map<Integer, List<Integer>> map = list.stream()
.collect(Collectors.groupingBy(
Collection::size,
Collectors.collectingAndThen(
Collectors.mapping(
l -> l.stream().filter(i -> i % 2 == 0).collect(Collectors.toList()),
Collectors.toList()),
i -> i.stream().flatMap(j -> j.stream()).collect(Collectors.toList()))));
Is there a shorter better way using solely java-8?
java java-8 java-stream java-9 collectors
add a comment |
I got in touch with a new feature since java-9 called Collectors.flatMapping
that takes place as a downstream of grouping or partitioning. Such as (example taken from here):
List<List<Integer>> list = Arrays.asList(
Arrays.asList(1, 2, 3, 4, 5, 6),
Arrays.asList(7, 8, 9, 10));
Map<Integer, List<Integer>> map =list.stream()
.collect(Collectors.groupingBy(
Collection::size,
Collectors.flatMapping(
l -> l.stream().filter(i -> i % 2 == 0),
Collectors.toList())));
{4=[8, 10], 6=[2, 4, 6]}
This is a fairly elegant way using just 3 collectors. I need to rewrite the collector in java-8 where is not yet supported. My attempt use 6 Collectors that is quite an extensive usage and I am not able to figure out a way using less of them:
Map<Integer, List<Integer>> map = list.stream()
.collect(Collectors.groupingBy(
Collection::size,
Collectors.collectingAndThen(
Collectors.mapping(
l -> l.stream().filter(i -> i % 2 == 0).collect(Collectors.toList()),
Collectors.toList()),
i -> i.stream().flatMap(j -> j.stream()).collect(Collectors.toList()))));
Is there a shorter better way using solely java-8?
java java-8 java-stream java-9 collectors
5
Can't you just backportflatMapping
? I just tried and it only requires 2 methods and 1 class, with no other dependencies. Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.
– Michael
Jan 21 at 10:06
4
@Michael agreed, you should post a version of this back-port actually, would be glad to upvote. I thought there would be already one by Holger, but I can't find it on stack overflow...
– Eugene
Jan 21 at 10:13
5
found it...
– Eugene
Jan 21 at 10:23
3
@Eugene He's always 1 step ahead
– Michael
Jan 21 at 10:24
add a comment |
I got in touch with a new feature since java-9 called Collectors.flatMapping
that takes place as a downstream of grouping or partitioning. Such as (example taken from here):
List<List<Integer>> list = Arrays.asList(
Arrays.asList(1, 2, 3, 4, 5, 6),
Arrays.asList(7, 8, 9, 10));
Map<Integer, List<Integer>> map =list.stream()
.collect(Collectors.groupingBy(
Collection::size,
Collectors.flatMapping(
l -> l.stream().filter(i -> i % 2 == 0),
Collectors.toList())));
{4=[8, 10], 6=[2, 4, 6]}
This is a fairly elegant way using just 3 collectors. I need to rewrite the collector in java-8 where is not yet supported. My attempt use 6 Collectors that is quite an extensive usage and I am not able to figure out a way using less of them:
Map<Integer, List<Integer>> map = list.stream()
.collect(Collectors.groupingBy(
Collection::size,
Collectors.collectingAndThen(
Collectors.mapping(
l -> l.stream().filter(i -> i % 2 == 0).collect(Collectors.toList()),
Collectors.toList()),
i -> i.stream().flatMap(j -> j.stream()).collect(Collectors.toList()))));
Is there a shorter better way using solely java-8?
java java-8 java-stream java-9 collectors
I got in touch with a new feature since java-9 called Collectors.flatMapping
that takes place as a downstream of grouping or partitioning. Such as (example taken from here):
List<List<Integer>> list = Arrays.asList(
Arrays.asList(1, 2, 3, 4, 5, 6),
Arrays.asList(7, 8, 9, 10));
Map<Integer, List<Integer>> map =list.stream()
.collect(Collectors.groupingBy(
Collection::size,
Collectors.flatMapping(
l -> l.stream().filter(i -> i % 2 == 0),
Collectors.toList())));
{4=[8, 10], 6=[2, 4, 6]}
This is a fairly elegant way using just 3 collectors. I need to rewrite the collector in java-8 where is not yet supported. My attempt use 6 Collectors that is quite an extensive usage and I am not able to figure out a way using less of them:
Map<Integer, List<Integer>> map = list.stream()
.collect(Collectors.groupingBy(
Collection::size,
Collectors.collectingAndThen(
Collectors.mapping(
l -> l.stream().filter(i -> i % 2 == 0).collect(Collectors.toList()),
Collectors.toList()),
i -> i.stream().flatMap(j -> j.stream()).collect(Collectors.toList()))));
Is there a shorter better way using solely java-8?
java java-8 java-stream java-9 collectors
java java-8 java-stream java-9 collectors
edited Jan 22 at 17:14
Steephen
7,85342232
7,85342232
asked Jan 21 at 10:00
NikolasNikolas
13.4k53568
13.4k53568
5
Can't you just backportflatMapping
? I just tried and it only requires 2 methods and 1 class, with no other dependencies. Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.
– Michael
Jan 21 at 10:06
4
@Michael agreed, you should post a version of this back-port actually, would be glad to upvote. I thought there would be already one by Holger, but I can't find it on stack overflow...
– Eugene
Jan 21 at 10:13
5
found it...
– Eugene
Jan 21 at 10:23
3
@Eugene He's always 1 step ahead
– Michael
Jan 21 at 10:24
add a comment |
5
Can't you just backportflatMapping
? I just tried and it only requires 2 methods and 1 class, with no other dependencies. Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.
– Michael
Jan 21 at 10:06
4
@Michael agreed, you should post a version of this back-port actually, would be glad to upvote. I thought there would be already one by Holger, but I can't find it on stack overflow...
– Eugene
Jan 21 at 10:13
5
found it...
– Eugene
Jan 21 at 10:23
3
@Eugene He's always 1 step ahead
– Michael
Jan 21 at 10:24
5
5
Can't you just backport
flatMapping
? I just tried and it only requires 2 methods and 1 class, with no other dependencies. Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.– Michael
Jan 21 at 10:06
Can't you just backport
flatMapping
? I just tried and it only requires 2 methods and 1 class, with no other dependencies. Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.– Michael
Jan 21 at 10:06
4
4
@Michael agreed, you should post a version of this back-port actually, would be glad to upvote. I thought there would be already one by Holger, but I can't find it on stack overflow...
– Eugene
Jan 21 at 10:13
@Michael agreed, you should post a version of this back-port actually, would be glad to upvote. I thought there would be already one by Holger, but I can't find it on stack overflow...
– Eugene
Jan 21 at 10:13
5
5
found it...
– Eugene
Jan 21 at 10:23
found it...
– Eugene
Jan 21 at 10:23
3
3
@Eugene He's always 1 step ahead
– Michael
Jan 21 at 10:24
@Eugene He's always 1 step ahead
– Michael
Jan 21 at 10:24
add a comment |
2 Answers
2
active
oldest
votes
For just this particular case, I guess this would be a simpler version:
Map<Integer, List<Integer>> map =
list.stream()
.collect(Collectors.toMap(
Collection::size,
x -> x.stream().filter(y -> y % 2 == 0).collect(Collectors.toList())
));
If there would be merging involved (two collections that would have the same size), I would add a merge
function that is pretty trivial:
Map<Integer, List<Integer>> map =
list.stream()
.collect(Collectors.toMap(
Collection::size,
x -> x.stream().filter(y -> y % 2 == 0).collect(Collectors.toCollection(ArrayList::new)),
(left, right) -> {
left.addAll(right);
return left;
}
));
Otherwise, I agree with Michael in this comment, this is not that hard to back-port to java-8.
add a comment |
I would just backport flatMapping
. It only requires 2 methods and 1 class, with no other dependencies.
Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.
The following code is taken from the JDK. I didn't write it. I have tested it with your example and it returns the same result.
Holger has written a shorter version, if you want to use that. I would trust it just as much but I haven't tested it.
class Nikollectors
{
public static <T, U, A, R> Collector<T, ?, R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper, Collector<? super U, A, R> downstream) {
BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
return new CollectorImpl<>(downstream.supplier(),
(r, t) -> {
try (Stream<? extends U> result = mapper.apply(t)) {
if (result != null)
result.sequential().forEach(u -> downstreamAccumulator.accept(r, u));
}
},
downstream.combiner(), downstream.finisher(),
downstream.characteristics());
}
private static class CollectorImpl<T, A, R> implements Collector<T, A, R>
{
private final Supplier<A> supplier;
private final BiConsumer<A, T> accumulator;
private final BinaryOperator<A> combiner;
private final Function<A, R> finisher;
private final Set<Characteristics> characteristics;
CollectorImpl(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Function<A,R> finisher,
Set<Characteristics> characteristics) {
this.supplier = supplier;
this.accumulator = accumulator;
this.combiner = combiner;
this.finisher = finisher;
this.characteristics = characteristics;
}
CollectorImpl(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Set<Characteristics> characteristics) {
this(supplier, accumulator, combiner, castingIdentity(), characteristics);
}
@Override
public BiConsumer<A, T> accumulator() {
return accumulator;
}
@Override
public Supplier<A> supplier() {
return supplier;
}
@Override
public BinaryOperator<A> combiner() {
return combiner;
}
@Override
public Function<A, R> finisher() {
return finisher;
}
@Override
public Set<Characteristics> characteristics() {
return characteristics;
}
}
private static <I, R> Function<I, R> castingIdentity() {
return i -> (R) i;
}
}
Sample usage:
Map<Integer, List<Integer>> map =list.stream()
.collect(Collectors.groupingBy(
Collection::size,
Nikollectors.flatMapping( // <<<
l -> l.stream().filter(i -> i % 2 == 0),
Collectors.toList()
)
)
);
5
you deserve two upvotes forNikollectors
... you should add an example of the usage too and may be a static factory method that would return thisCollectors::flatMapping
to make it a full example IMHO
– Eugene
Jan 21 at 10:17
6
you might be joking, but in my project we have a packagexxx.HolgerUtil
- just to be sure where this was taken from, no joke. :)
– Eugene
Jan 21 at 10:21
2
You both made my day. :D Thanks for the answers and useful links.
– Nikolas
Jan 21 at 11:27
3
@Flown Holger's already done that, which I am linking to. The point wasn't so much just to show any old implementation, but rather to show (as much as possible) the approach I would first pursue whenever I require any future JDK functionality. And that would involve a copy-paste, not writing it myself from scratch. Brevity is not important for me here because I would put it into a util class and probably never look at it again.
– Michael
Jan 21 at 11:46
3
@Michael just doing copy&paste can be quiet dangerous, so it’s very recommended to still use it only when you understand it completely. The main difference to my version is, that the JDK internal code uses aCollectorImpl
class, because, in the end, there has to be an actual implementation class for theCollector
interface. In your application code, you can useCollector.of(…)
instead, which will use the JRE provided, non-public implementation class.
– Holger
Jan 21 at 13:29
|
show 5 more comments
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54287457%2fjava-9-collectors-flatmapping-rewritten-in-java-8%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
For just this particular case, I guess this would be a simpler version:
Map<Integer, List<Integer>> map =
list.stream()
.collect(Collectors.toMap(
Collection::size,
x -> x.stream().filter(y -> y % 2 == 0).collect(Collectors.toList())
));
If there would be merging involved (two collections that would have the same size), I would add a merge
function that is pretty trivial:
Map<Integer, List<Integer>> map =
list.stream()
.collect(Collectors.toMap(
Collection::size,
x -> x.stream().filter(y -> y % 2 == 0).collect(Collectors.toCollection(ArrayList::new)),
(left, right) -> {
left.addAll(right);
return left;
}
));
Otherwise, I agree with Michael in this comment, this is not that hard to back-port to java-8.
add a comment |
For just this particular case, I guess this would be a simpler version:
Map<Integer, List<Integer>> map =
list.stream()
.collect(Collectors.toMap(
Collection::size,
x -> x.stream().filter(y -> y % 2 == 0).collect(Collectors.toList())
));
If there would be merging involved (two collections that would have the same size), I would add a merge
function that is pretty trivial:
Map<Integer, List<Integer>> map =
list.stream()
.collect(Collectors.toMap(
Collection::size,
x -> x.stream().filter(y -> y % 2 == 0).collect(Collectors.toCollection(ArrayList::new)),
(left, right) -> {
left.addAll(right);
return left;
}
));
Otherwise, I agree with Michael in this comment, this is not that hard to back-port to java-8.
add a comment |
For just this particular case, I guess this would be a simpler version:
Map<Integer, List<Integer>> map =
list.stream()
.collect(Collectors.toMap(
Collection::size,
x -> x.stream().filter(y -> y % 2 == 0).collect(Collectors.toList())
));
If there would be merging involved (two collections that would have the same size), I would add a merge
function that is pretty trivial:
Map<Integer, List<Integer>> map =
list.stream()
.collect(Collectors.toMap(
Collection::size,
x -> x.stream().filter(y -> y % 2 == 0).collect(Collectors.toCollection(ArrayList::new)),
(left, right) -> {
left.addAll(right);
return left;
}
));
Otherwise, I agree with Michael in this comment, this is not that hard to back-port to java-8.
For just this particular case, I guess this would be a simpler version:
Map<Integer, List<Integer>> map =
list.stream()
.collect(Collectors.toMap(
Collection::size,
x -> x.stream().filter(y -> y % 2 == 0).collect(Collectors.toList())
));
If there would be merging involved (two collections that would have the same size), I would add a merge
function that is pretty trivial:
Map<Integer, List<Integer>> map =
list.stream()
.collect(Collectors.toMap(
Collection::size,
x -> x.stream().filter(y -> y % 2 == 0).collect(Collectors.toCollection(ArrayList::new)),
(left, right) -> {
left.addAll(right);
return left;
}
));
Otherwise, I agree with Michael in this comment, this is not that hard to back-port to java-8.
answered Jan 21 at 10:12
EugeneEugene
70.6k9102169
70.6k9102169
add a comment |
add a comment |
I would just backport flatMapping
. It only requires 2 methods and 1 class, with no other dependencies.
Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.
The following code is taken from the JDK. I didn't write it. I have tested it with your example and it returns the same result.
Holger has written a shorter version, if you want to use that. I would trust it just as much but I haven't tested it.
class Nikollectors
{
public static <T, U, A, R> Collector<T, ?, R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper, Collector<? super U, A, R> downstream) {
BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
return new CollectorImpl<>(downstream.supplier(),
(r, t) -> {
try (Stream<? extends U> result = mapper.apply(t)) {
if (result != null)
result.sequential().forEach(u -> downstreamAccumulator.accept(r, u));
}
},
downstream.combiner(), downstream.finisher(),
downstream.characteristics());
}
private static class CollectorImpl<T, A, R> implements Collector<T, A, R>
{
private final Supplier<A> supplier;
private final BiConsumer<A, T> accumulator;
private final BinaryOperator<A> combiner;
private final Function<A, R> finisher;
private final Set<Characteristics> characteristics;
CollectorImpl(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Function<A,R> finisher,
Set<Characteristics> characteristics) {
this.supplier = supplier;
this.accumulator = accumulator;
this.combiner = combiner;
this.finisher = finisher;
this.characteristics = characteristics;
}
CollectorImpl(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Set<Characteristics> characteristics) {
this(supplier, accumulator, combiner, castingIdentity(), characteristics);
}
@Override
public BiConsumer<A, T> accumulator() {
return accumulator;
}
@Override
public Supplier<A> supplier() {
return supplier;
}
@Override
public BinaryOperator<A> combiner() {
return combiner;
}
@Override
public Function<A, R> finisher() {
return finisher;
}
@Override
public Set<Characteristics> characteristics() {
return characteristics;
}
}
private static <I, R> Function<I, R> castingIdentity() {
return i -> (R) i;
}
}
Sample usage:
Map<Integer, List<Integer>> map =list.stream()
.collect(Collectors.groupingBy(
Collection::size,
Nikollectors.flatMapping( // <<<
l -> l.stream().filter(i -> i % 2 == 0),
Collectors.toList()
)
)
);
5
you deserve two upvotes forNikollectors
... you should add an example of the usage too and may be a static factory method that would return thisCollectors::flatMapping
to make it a full example IMHO
– Eugene
Jan 21 at 10:17
6
you might be joking, but in my project we have a packagexxx.HolgerUtil
- just to be sure where this was taken from, no joke. :)
– Eugene
Jan 21 at 10:21
2
You both made my day. :D Thanks for the answers and useful links.
– Nikolas
Jan 21 at 11:27
3
@Flown Holger's already done that, which I am linking to. The point wasn't so much just to show any old implementation, but rather to show (as much as possible) the approach I would first pursue whenever I require any future JDK functionality. And that would involve a copy-paste, not writing it myself from scratch. Brevity is not important for me here because I would put it into a util class and probably never look at it again.
– Michael
Jan 21 at 11:46
3
@Michael just doing copy&paste can be quiet dangerous, so it’s very recommended to still use it only when you understand it completely. The main difference to my version is, that the JDK internal code uses aCollectorImpl
class, because, in the end, there has to be an actual implementation class for theCollector
interface. In your application code, you can useCollector.of(…)
instead, which will use the JRE provided, non-public implementation class.
– Holger
Jan 21 at 13:29
|
show 5 more comments
I would just backport flatMapping
. It only requires 2 methods and 1 class, with no other dependencies.
Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.
The following code is taken from the JDK. I didn't write it. I have tested it with your example and it returns the same result.
Holger has written a shorter version, if you want to use that. I would trust it just as much but I haven't tested it.
class Nikollectors
{
public static <T, U, A, R> Collector<T, ?, R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper, Collector<? super U, A, R> downstream) {
BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
return new CollectorImpl<>(downstream.supplier(),
(r, t) -> {
try (Stream<? extends U> result = mapper.apply(t)) {
if (result != null)
result.sequential().forEach(u -> downstreamAccumulator.accept(r, u));
}
},
downstream.combiner(), downstream.finisher(),
downstream.characteristics());
}
private static class CollectorImpl<T, A, R> implements Collector<T, A, R>
{
private final Supplier<A> supplier;
private final BiConsumer<A, T> accumulator;
private final BinaryOperator<A> combiner;
private final Function<A, R> finisher;
private final Set<Characteristics> characteristics;
CollectorImpl(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Function<A,R> finisher,
Set<Characteristics> characteristics) {
this.supplier = supplier;
this.accumulator = accumulator;
this.combiner = combiner;
this.finisher = finisher;
this.characteristics = characteristics;
}
CollectorImpl(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Set<Characteristics> characteristics) {
this(supplier, accumulator, combiner, castingIdentity(), characteristics);
}
@Override
public BiConsumer<A, T> accumulator() {
return accumulator;
}
@Override
public Supplier<A> supplier() {
return supplier;
}
@Override
public BinaryOperator<A> combiner() {
return combiner;
}
@Override
public Function<A, R> finisher() {
return finisher;
}
@Override
public Set<Characteristics> characteristics() {
return characteristics;
}
}
private static <I, R> Function<I, R> castingIdentity() {
return i -> (R) i;
}
}
Sample usage:
Map<Integer, List<Integer>> map =list.stream()
.collect(Collectors.groupingBy(
Collection::size,
Nikollectors.flatMapping( // <<<
l -> l.stream().filter(i -> i % 2 == 0),
Collectors.toList()
)
)
);
5
you deserve two upvotes forNikollectors
... you should add an example of the usage too and may be a static factory method that would return thisCollectors::flatMapping
to make it a full example IMHO
– Eugene
Jan 21 at 10:17
6
you might be joking, but in my project we have a packagexxx.HolgerUtil
- just to be sure where this was taken from, no joke. :)
– Eugene
Jan 21 at 10:21
2
You both made my day. :D Thanks for the answers and useful links.
– Nikolas
Jan 21 at 11:27
3
@Flown Holger's already done that, which I am linking to. The point wasn't so much just to show any old implementation, but rather to show (as much as possible) the approach I would first pursue whenever I require any future JDK functionality. And that would involve a copy-paste, not writing it myself from scratch. Brevity is not important for me here because I would put it into a util class and probably never look at it again.
– Michael
Jan 21 at 11:46
3
@Michael just doing copy&paste can be quiet dangerous, so it’s very recommended to still use it only when you understand it completely. The main difference to my version is, that the JDK internal code uses aCollectorImpl
class, because, in the end, there has to be an actual implementation class for theCollector
interface. In your application code, you can useCollector.of(…)
instead, which will use the JRE provided, non-public implementation class.
– Holger
Jan 21 at 13:29
|
show 5 more comments
I would just backport flatMapping
. It only requires 2 methods and 1 class, with no other dependencies.
Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.
The following code is taken from the JDK. I didn't write it. I have tested it with your example and it returns the same result.
Holger has written a shorter version, if you want to use that. I would trust it just as much but I haven't tested it.
class Nikollectors
{
public static <T, U, A, R> Collector<T, ?, R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper, Collector<? super U, A, R> downstream) {
BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
return new CollectorImpl<>(downstream.supplier(),
(r, t) -> {
try (Stream<? extends U> result = mapper.apply(t)) {
if (result != null)
result.sequential().forEach(u -> downstreamAccumulator.accept(r, u));
}
},
downstream.combiner(), downstream.finisher(),
downstream.characteristics());
}
private static class CollectorImpl<T, A, R> implements Collector<T, A, R>
{
private final Supplier<A> supplier;
private final BiConsumer<A, T> accumulator;
private final BinaryOperator<A> combiner;
private final Function<A, R> finisher;
private final Set<Characteristics> characteristics;
CollectorImpl(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Function<A,R> finisher,
Set<Characteristics> characteristics) {
this.supplier = supplier;
this.accumulator = accumulator;
this.combiner = combiner;
this.finisher = finisher;
this.characteristics = characteristics;
}
CollectorImpl(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Set<Characteristics> characteristics) {
this(supplier, accumulator, combiner, castingIdentity(), characteristics);
}
@Override
public BiConsumer<A, T> accumulator() {
return accumulator;
}
@Override
public Supplier<A> supplier() {
return supplier;
}
@Override
public BinaryOperator<A> combiner() {
return combiner;
}
@Override
public Function<A, R> finisher() {
return finisher;
}
@Override
public Set<Characteristics> characteristics() {
return characteristics;
}
}
private static <I, R> Function<I, R> castingIdentity() {
return i -> (R) i;
}
}
Sample usage:
Map<Integer, List<Integer>> map =list.stream()
.collect(Collectors.groupingBy(
Collection::size,
Nikollectors.flatMapping( // <<<
l -> l.stream().filter(i -> i % 2 == 0),
Collectors.toList()
)
)
);
I would just backport flatMapping
. It only requires 2 methods and 1 class, with no other dependencies.
Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.
The following code is taken from the JDK. I didn't write it. I have tested it with your example and it returns the same result.
Holger has written a shorter version, if you want to use that. I would trust it just as much but I haven't tested it.
class Nikollectors
{
public static <T, U, A, R> Collector<T, ?, R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper, Collector<? super U, A, R> downstream) {
BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
return new CollectorImpl<>(downstream.supplier(),
(r, t) -> {
try (Stream<? extends U> result = mapper.apply(t)) {
if (result != null)
result.sequential().forEach(u -> downstreamAccumulator.accept(r, u));
}
},
downstream.combiner(), downstream.finisher(),
downstream.characteristics());
}
private static class CollectorImpl<T, A, R> implements Collector<T, A, R>
{
private final Supplier<A> supplier;
private final BiConsumer<A, T> accumulator;
private final BinaryOperator<A> combiner;
private final Function<A, R> finisher;
private final Set<Characteristics> characteristics;
CollectorImpl(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Function<A,R> finisher,
Set<Characteristics> characteristics) {
this.supplier = supplier;
this.accumulator = accumulator;
this.combiner = combiner;
this.finisher = finisher;
this.characteristics = characteristics;
}
CollectorImpl(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Set<Characteristics> characteristics) {
this(supplier, accumulator, combiner, castingIdentity(), characteristics);
}
@Override
public BiConsumer<A, T> accumulator() {
return accumulator;
}
@Override
public Supplier<A> supplier() {
return supplier;
}
@Override
public BinaryOperator<A> combiner() {
return combiner;
}
@Override
public Function<A, R> finisher() {
return finisher;
}
@Override
public Set<Characteristics> characteristics() {
return characteristics;
}
}
private static <I, R> Function<I, R> castingIdentity() {
return i -> (R) i;
}
}
Sample usage:
Map<Integer, List<Integer>> map =list.stream()
.collect(Collectors.groupingBy(
Collection::size,
Nikollectors.flatMapping( // <<<
l -> l.stream().filter(i -> i % 2 == 0),
Collectors.toList()
)
)
);
edited Jan 21 at 10:22
answered Jan 21 at 10:16
MichaelMichael
20.6k83471
20.6k83471
5
you deserve two upvotes forNikollectors
... you should add an example of the usage too and may be a static factory method that would return thisCollectors::flatMapping
to make it a full example IMHO
– Eugene
Jan 21 at 10:17
6
you might be joking, but in my project we have a packagexxx.HolgerUtil
- just to be sure where this was taken from, no joke. :)
– Eugene
Jan 21 at 10:21
2
You both made my day. :D Thanks for the answers and useful links.
– Nikolas
Jan 21 at 11:27
3
@Flown Holger's already done that, which I am linking to. The point wasn't so much just to show any old implementation, but rather to show (as much as possible) the approach I would first pursue whenever I require any future JDK functionality. And that would involve a copy-paste, not writing it myself from scratch. Brevity is not important for me here because I would put it into a util class and probably never look at it again.
– Michael
Jan 21 at 11:46
3
@Michael just doing copy&paste can be quiet dangerous, so it’s very recommended to still use it only when you understand it completely. The main difference to my version is, that the JDK internal code uses aCollectorImpl
class, because, in the end, there has to be an actual implementation class for theCollector
interface. In your application code, you can useCollector.of(…)
instead, which will use the JRE provided, non-public implementation class.
– Holger
Jan 21 at 13:29
|
show 5 more comments
5
you deserve two upvotes forNikollectors
... you should add an example of the usage too and may be a static factory method that would return thisCollectors::flatMapping
to make it a full example IMHO
– Eugene
Jan 21 at 10:17
6
you might be joking, but in my project we have a packagexxx.HolgerUtil
- just to be sure where this was taken from, no joke. :)
– Eugene
Jan 21 at 10:21
2
You both made my day. :D Thanks for the answers and useful links.
– Nikolas
Jan 21 at 11:27
3
@Flown Holger's already done that, which I am linking to. The point wasn't so much just to show any old implementation, but rather to show (as much as possible) the approach I would first pursue whenever I require any future JDK functionality. And that would involve a copy-paste, not writing it myself from scratch. Brevity is not important for me here because I would put it into a util class and probably never look at it again.
– Michael
Jan 21 at 11:46
3
@Michael just doing copy&paste can be quiet dangerous, so it’s very recommended to still use it only when you understand it completely. The main difference to my version is, that the JDK internal code uses aCollectorImpl
class, because, in the end, there has to be an actual implementation class for theCollector
interface. In your application code, you can useCollector.of(…)
instead, which will use the JRE provided, non-public implementation class.
– Holger
Jan 21 at 13:29
5
5
you deserve two upvotes for
Nikollectors
... you should add an example of the usage too and may be a static factory method that would return this Collectors::flatMapping
to make it a full example IMHO– Eugene
Jan 21 at 10:17
you deserve two upvotes for
Nikollectors
... you should add an example of the usage too and may be a static factory method that would return this Collectors::flatMapping
to make it a full example IMHO– Eugene
Jan 21 at 10:17
6
6
you might be joking, but in my project we have a package
xxx.HolgerUtil
- just to be sure where this was taken from, no joke. :)– Eugene
Jan 21 at 10:21
you might be joking, but in my project we have a package
xxx.HolgerUtil
- just to be sure where this was taken from, no joke. :)– Eugene
Jan 21 at 10:21
2
2
You both made my day. :D Thanks for the answers and useful links.
– Nikolas
Jan 21 at 11:27
You both made my day. :D Thanks for the answers and useful links.
– Nikolas
Jan 21 at 11:27
3
3
@Flown Holger's already done that, which I am linking to. The point wasn't so much just to show any old implementation, but rather to show (as much as possible) the approach I would first pursue whenever I require any future JDK functionality. And that would involve a copy-paste, not writing it myself from scratch. Brevity is not important for me here because I would put it into a util class and probably never look at it again.
– Michael
Jan 21 at 11:46
@Flown Holger's already done that, which I am linking to. The point wasn't so much just to show any old implementation, but rather to show (as much as possible) the approach I would first pursue whenever I require any future JDK functionality. And that would involve a copy-paste, not writing it myself from scratch. Brevity is not important for me here because I would put it into a util class and probably never look at it again.
– Michael
Jan 21 at 11:46
3
3
@Michael just doing copy&paste can be quiet dangerous, so it’s very recommended to still use it only when you understand it completely. The main difference to my version is, that the JDK internal code uses a
CollectorImpl
class, because, in the end, there has to be an actual implementation class for the Collector
interface. In your application code, you can use Collector.of(…)
instead, which will use the JRE provided, non-public implementation class.– Holger
Jan 21 at 13:29
@Michael just doing copy&paste can be quiet dangerous, so it’s very recommended to still use it only when you understand it completely. The main difference to my version is, that the JDK internal code uses a
CollectorImpl
class, because, in the end, there has to be an actual implementation class for the Collector
interface. In your application code, you can use Collector.of(…)
instead, which will use the JRE provided, non-public implementation class.– Holger
Jan 21 at 13:29
|
show 5 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54287457%2fjava-9-collectors-flatmapping-rewritten-in-java-8%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
5
Can't you just backport
flatMapping
? I just tried and it only requires 2 methods and 1 class, with no other dependencies. Also, when it comes time to upgrade to Java 9, you can just deprecate your version and replace any usages of it with the proper version.– Michael
Jan 21 at 10:06
4
@Michael agreed, you should post a version of this back-port actually, would be glad to upvote. I thought there would be already one by Holger, but I can't find it on stack overflow...
– Eugene
Jan 21 at 10:13
5
found it...
– Eugene
Jan 21 at 10:23
3
@Eugene He's always 1 step ahead
– Michael
Jan 21 at 10:24