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
2 days ago
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
2 days ago
5
found it...
– Eugene
2 days ago
3
@Eugene He's always 1 step ahead
– Michael
2 days ago
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 yesterday
Steephen
7,74342232
7,74342232
asked 2 days ago
NikolasNikolas
13.4k53468
13.4k53468
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
2 days ago
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
2 days ago
5
found it...
– Eugene
2 days ago
3
@Eugene He's always 1 step ahead
– Michael
2 days ago
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
2 days ago
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
2 days ago
5
found it...
– Eugene
2 days ago
3
@Eugene He's always 1 step ahead
– Michael
2 days ago
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
2 days ago
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
2 days ago
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
2 days ago
@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
2 days ago
5
5
found it...
– Eugene
2 days ago
found it...
– Eugene
2 days ago
3
3
@Eugene He's always 1 step ahead
– Michael
2 days ago
@Eugene He's always 1 step ahead
– Michael
2 days ago
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
2 days ago
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
2 days ago
2
You both made my day. :D Thanks for the answers and useful links.
– Nikolas
2 days ago
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
2 days ago
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
2 days ago
|
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 2 days ago
EugeneEugene
69.6k999164
69.6k999164
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
2 days ago
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
2 days ago
2
You both made my day. :D Thanks for the answers and useful links.
– Nikolas
2 days ago
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
2 days ago
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
2 days ago
|
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
2 days ago
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
2 days ago
2
You both made my day. :D Thanks for the answers and useful links.
– Nikolas
2 days ago
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
2 days ago
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
2 days ago
|
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 2 days ago
answered 2 days ago
MichaelMichael
19.6k73470
19.6k73470
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
2 days ago
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
2 days ago
2
You both made my day. :D Thanks for the answers and useful links.
– Nikolas
2 days ago
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
2 days ago
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
2 days ago
|
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
2 days ago
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
2 days ago
2
You both made my day. :D Thanks for the answers and useful links.
– Nikolas
2 days ago
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
2 days ago
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
2 days ago
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
2 days ago
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
2 days ago
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
2 days ago
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
2 days ago
2
2
You both made my day. :D Thanks for the answers and useful links.
– Nikolas
2 days ago
You both made my day. :D Thanks for the answers and useful links.
– Nikolas
2 days ago
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
2 days ago
@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
2 days ago
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
2 days ago
@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
2 days ago
|
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
2 days ago
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
2 days ago
5
found it...
– Eugene
2 days ago
3
@Eugene He's always 1 step ahead
– Michael
2 days ago