Java 8 list processing - add elements conditionally
I have the following piece of code:
List<Object> list = new ArrayList<>();
list.addAll(method1());
if(list.isEmpty()) { list.addAll(method2()); }
if(list.isEmpty()) { list.addAll(method3()); }
if(list.isEmpty()) { list.addAll(method4()); }
if(list.isEmpty()) { list.addAll(method5()); }
if(list.isEmpty()) { list.addAll(method6()); }
return list;
Is there a nice way to add elements conditionally, maybe using stream operations? I would like to add elements from method2 only if the list is empty otherwise return and so on.
Edit: It's worth to mention that the methods contain heavy logic so need to be prevented from execution.
java collections java-8 stream
add a comment |
I have the following piece of code:
List<Object> list = new ArrayList<>();
list.addAll(method1());
if(list.isEmpty()) { list.addAll(method2()); }
if(list.isEmpty()) { list.addAll(method3()); }
if(list.isEmpty()) { list.addAll(method4()); }
if(list.isEmpty()) { list.addAll(method5()); }
if(list.isEmpty()) { list.addAll(method6()); }
return list;
Is there a nice way to add elements conditionally, maybe using stream operations? I would like to add elements from method2 only if the list is empty otherwise return and so on.
Edit: It's worth to mention that the methods contain heavy logic so need to be prevented from execution.
java collections java-8 stream
1
I don't think there's a faster way to do it.
– gbandres
1 hour ago
add a comment |
I have the following piece of code:
List<Object> list = new ArrayList<>();
list.addAll(method1());
if(list.isEmpty()) { list.addAll(method2()); }
if(list.isEmpty()) { list.addAll(method3()); }
if(list.isEmpty()) { list.addAll(method4()); }
if(list.isEmpty()) { list.addAll(method5()); }
if(list.isEmpty()) { list.addAll(method6()); }
return list;
Is there a nice way to add elements conditionally, maybe using stream operations? I would like to add elements from method2 only if the list is empty otherwise return and so on.
Edit: It's worth to mention that the methods contain heavy logic so need to be prevented from execution.
java collections java-8 stream
I have the following piece of code:
List<Object> list = new ArrayList<>();
list.addAll(method1());
if(list.isEmpty()) { list.addAll(method2()); }
if(list.isEmpty()) { list.addAll(method3()); }
if(list.isEmpty()) { list.addAll(method4()); }
if(list.isEmpty()) { list.addAll(method5()); }
if(list.isEmpty()) { list.addAll(method6()); }
return list;
Is there a nice way to add elements conditionally, maybe using stream operations? I would like to add elements from method2 only if the list is empty otherwise return and so on.
Edit: It's worth to mention that the methods contain heavy logic so need to be prevented from execution.
java collections java-8 stream
java collections java-8 stream
edited 42 mins ago
asked 1 hour ago
ionut
705
705
1
I don't think there's a faster way to do it.
– gbandres
1 hour ago
add a comment |
1
I don't think there's a faster way to do it.
– gbandres
1 hour ago
1
1
I don't think there's a faster way to do it.
– gbandres
1 hour ago
I don't think there's a faster way to do it.
– gbandres
1 hour ago
add a comment |
6 Answers
6
active
oldest
votes
I would simply use a stream of suppliers and filter on List.isEmpty
:
Stream.<Supplier<List<Object>>>of(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6())
.map(Supplier<List<Object>>::get)
.filter(l -> !l.isEmpty())
.findFirst()
.ifPresent(list::addAll);
return list;
findFirst()
will prevent unnecessary calls to methodN()
when the first non-empty list is returned by one of the methods.
EDIT:
As remarked in comments below, if your list
object is not initialized with anything else, then it makes sense to just return the result of the stream directly:
return Stream.<Supplier<List<Object>>>of(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6())
.map(Supplier<List<Object>>::get)
.filter(l -> !l.isEmpty())
.findFirst()
.orElseGet(ArrayList::new);
3
Worth to note that, ifmethodX()
returns aList
and not another type ofCollection
, it might be possible to return that list directly, instead of creating a new list and adding to that:.map(Supplier::get).filter(s -> !s.isEmpty()).findFirst().orElse(emptyList());
. Whether this is appropriate or not is not possible to determine from the question.
– Magnilex
40 mins ago
By the way, do you know why you have to explicitly state the type<Supplier<List<Object>>>
to the factory method because the compiler cannot infer the type itself? I had the same issue.
– Ricola
28 mins ago
@Ricola Without defining it explicitly, the compiler doesn't know the target type of lambda expressions. The alternative would have been to do it in two steps, explicitly declaring aStream<Supplier<List<Object>>>
as the type of the stream.
– ernest_k
24 mins ago
add a comment |
You could try to check the return value of addAll
. It will return true
whenever the list has been modified, so try this:
List<Object> list = new ArrayList<>();
// ret unused, otherwise it doesn't compile
boolean ret = list.addAll(method1())
|| list.addAll(method2())
|| list.addAll(method3())
|| list.addAll(method4())
|| list.addAll(method5())
|| list.addAll(method6());
return list;
Because of lazy evaluation, the first addAll
operation that added at least one element will prevent the rest from bein called. I like the fact that "||" expresses the intent quite well.
1
one of the rare cases where one cares about the return value ofaddAll
. indeed very clever, efficient and readable! ;-).
– Aomine
11 mins ago
1
Agreed. I believe it can't get simpler or more readable than this.
– ernest_k
10 mins ago
add a comment |
A way of doing it without repeating yourself is to extract a method doing it for you:
private void addIfEmpty(List<Object> targetList, Supplier<Collection<?>> supplier) {
if (targetList.isEmpty()) {
targetList.addAll(supplier.get());
}
}
And then
List<Object> list = new ArrayList<>();
addIfEmpty(list, this::method1);
addIfEmpty(list, this::method2);
addIfEmpty(list, this::method3);
addIfEmpty(list, this::method4);
addIfEmpty(list, this::method5);
addIfEmpty(list, this::method6);
return list;
Or even use a for loop:
List<Supplier<Collection<?>>> suppliers = Arrays.asList(this::method1, this::method2, ...);
List<Object> list = new ArrayList<>();
suppliers.forEach(supplier -> this.addIfEmpty(list, supplier));
Now DRY is not the most important aspect. If you think your original code is easier to read and understand, then keep it like that.
You should rather name the methodaddIfEmpty
instead ofaddIfNotEmpty
– Ricola
35 mins ago
@Ricola good point, indeed.
– JB Nizet
23 mins ago
add a comment |
You could create a method as such:
public static List<Object> lazyVersion(Supplier<List<Object>>... suppliers){
return Arrays.stream(suppliers)
.map(Supplier::get)
.filter(s -> !s.isEmpty()) // or .filter(Predicate.not(List::isEmpty)) as of JDK11
.findFirst()
.orElseGet(Collections::emptyList);
}
and then call it as follows:
lazyVersion(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6());
method name for illustration purposes only.
add a comment |
You could make your code nicer by creating the method
public void addAllIfEmpty(List<Object> list, Supplier<List<Object>> method){
if(list.isEmpty()){
list.addAll(method.get());
}
}
Then you can use it like this (I assumed your methods are not static methods, if they are you need to reference them using ClassName::method1
)
List<Object> list = new ArrayList<>();
list.addAll(method1());
addAllIfEmpty(list, this::method2);
addAllIfEmpty(list, this::method3);
addAllIfEmpty(list, this::method4);
addAllIfEmpty(list, this::method5);
addAllIfEmpty(list, this::method6);
return list;
If you really want to use a Stream, you could do this
Stream.<Supplier<List<Object>>>of(this::method1, this::method2, this::method3, this::method4, this::method5, this::method6)
.collect(ArrayList::new, this::addAllIfEmpty, ArrayList::addAll);
IMO it makes it more complicated, depending on how your methods are referenced, it might be better to use a loop
add a comment |
Java 8 streams weren't designed to support this kind of operation. From the jdk:
A stream should be operated on (invoking an intermediate or terminal stream operation) only once. This rules out, for example, "forked" streams, where the same source feeds two or more pipelines, or multiple traversals of the same stream.
If you can store it in memory you can use Collectors.partitioningBy
if you have just two types and go by with a Map<Boolean, List>
. Otherwise use Collectors.groupingBy
.
add a comment |
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%2f53957780%2fjava-8-list-processing-add-elements-conditionally%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
I would simply use a stream of suppliers and filter on List.isEmpty
:
Stream.<Supplier<List<Object>>>of(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6())
.map(Supplier<List<Object>>::get)
.filter(l -> !l.isEmpty())
.findFirst()
.ifPresent(list::addAll);
return list;
findFirst()
will prevent unnecessary calls to methodN()
when the first non-empty list is returned by one of the methods.
EDIT:
As remarked in comments below, if your list
object is not initialized with anything else, then it makes sense to just return the result of the stream directly:
return Stream.<Supplier<List<Object>>>of(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6())
.map(Supplier<List<Object>>::get)
.filter(l -> !l.isEmpty())
.findFirst()
.orElseGet(ArrayList::new);
3
Worth to note that, ifmethodX()
returns aList
and not another type ofCollection
, it might be possible to return that list directly, instead of creating a new list and adding to that:.map(Supplier::get).filter(s -> !s.isEmpty()).findFirst().orElse(emptyList());
. Whether this is appropriate or not is not possible to determine from the question.
– Magnilex
40 mins ago
By the way, do you know why you have to explicitly state the type<Supplier<List<Object>>>
to the factory method because the compiler cannot infer the type itself? I had the same issue.
– Ricola
28 mins ago
@Ricola Without defining it explicitly, the compiler doesn't know the target type of lambda expressions. The alternative would have been to do it in two steps, explicitly declaring aStream<Supplier<List<Object>>>
as the type of the stream.
– ernest_k
24 mins ago
add a comment |
I would simply use a stream of suppliers and filter on List.isEmpty
:
Stream.<Supplier<List<Object>>>of(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6())
.map(Supplier<List<Object>>::get)
.filter(l -> !l.isEmpty())
.findFirst()
.ifPresent(list::addAll);
return list;
findFirst()
will prevent unnecessary calls to methodN()
when the first non-empty list is returned by one of the methods.
EDIT:
As remarked in comments below, if your list
object is not initialized with anything else, then it makes sense to just return the result of the stream directly:
return Stream.<Supplier<List<Object>>>of(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6())
.map(Supplier<List<Object>>::get)
.filter(l -> !l.isEmpty())
.findFirst()
.orElseGet(ArrayList::new);
3
Worth to note that, ifmethodX()
returns aList
and not another type ofCollection
, it might be possible to return that list directly, instead of creating a new list and adding to that:.map(Supplier::get).filter(s -> !s.isEmpty()).findFirst().orElse(emptyList());
. Whether this is appropriate or not is not possible to determine from the question.
– Magnilex
40 mins ago
By the way, do you know why you have to explicitly state the type<Supplier<List<Object>>>
to the factory method because the compiler cannot infer the type itself? I had the same issue.
– Ricola
28 mins ago
@Ricola Without defining it explicitly, the compiler doesn't know the target type of lambda expressions. The alternative would have been to do it in two steps, explicitly declaring aStream<Supplier<List<Object>>>
as the type of the stream.
– ernest_k
24 mins ago
add a comment |
I would simply use a stream of suppliers and filter on List.isEmpty
:
Stream.<Supplier<List<Object>>>of(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6())
.map(Supplier<List<Object>>::get)
.filter(l -> !l.isEmpty())
.findFirst()
.ifPresent(list::addAll);
return list;
findFirst()
will prevent unnecessary calls to methodN()
when the first non-empty list is returned by one of the methods.
EDIT:
As remarked in comments below, if your list
object is not initialized with anything else, then it makes sense to just return the result of the stream directly:
return Stream.<Supplier<List<Object>>>of(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6())
.map(Supplier<List<Object>>::get)
.filter(l -> !l.isEmpty())
.findFirst()
.orElseGet(ArrayList::new);
I would simply use a stream of suppliers and filter on List.isEmpty
:
Stream.<Supplier<List<Object>>>of(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6())
.map(Supplier<List<Object>>::get)
.filter(l -> !l.isEmpty())
.findFirst()
.ifPresent(list::addAll);
return list;
findFirst()
will prevent unnecessary calls to methodN()
when the first non-empty list is returned by one of the methods.
EDIT:
As remarked in comments below, if your list
object is not initialized with anything else, then it makes sense to just return the result of the stream directly:
return Stream.<Supplier<List<Object>>>of(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6())
.map(Supplier<List<Object>>::get)
.filter(l -> !l.isEmpty())
.findFirst()
.orElseGet(ArrayList::new);
edited 22 mins ago
Aomine
39.2k73669
39.2k73669
answered 57 mins ago
ernest_k
19.6k41941
19.6k41941
3
Worth to note that, ifmethodX()
returns aList
and not another type ofCollection
, it might be possible to return that list directly, instead of creating a new list and adding to that:.map(Supplier::get).filter(s -> !s.isEmpty()).findFirst().orElse(emptyList());
. Whether this is appropriate or not is not possible to determine from the question.
– Magnilex
40 mins ago
By the way, do you know why you have to explicitly state the type<Supplier<List<Object>>>
to the factory method because the compiler cannot infer the type itself? I had the same issue.
– Ricola
28 mins ago
@Ricola Without defining it explicitly, the compiler doesn't know the target type of lambda expressions. The alternative would have been to do it in two steps, explicitly declaring aStream<Supplier<List<Object>>>
as the type of the stream.
– ernest_k
24 mins ago
add a comment |
3
Worth to note that, ifmethodX()
returns aList
and not another type ofCollection
, it might be possible to return that list directly, instead of creating a new list and adding to that:.map(Supplier::get).filter(s -> !s.isEmpty()).findFirst().orElse(emptyList());
. Whether this is appropriate or not is not possible to determine from the question.
– Magnilex
40 mins ago
By the way, do you know why you have to explicitly state the type<Supplier<List<Object>>>
to the factory method because the compiler cannot infer the type itself? I had the same issue.
– Ricola
28 mins ago
@Ricola Without defining it explicitly, the compiler doesn't know the target type of lambda expressions. The alternative would have been to do it in two steps, explicitly declaring aStream<Supplier<List<Object>>>
as the type of the stream.
– ernest_k
24 mins ago
3
3
Worth to note that, if
methodX()
returns a List
and not another type of Collection
, it might be possible to return that list directly, instead of creating a new list and adding to that: .map(Supplier::get).filter(s -> !s.isEmpty()).findFirst().orElse(emptyList());
. Whether this is appropriate or not is not possible to determine from the question.– Magnilex
40 mins ago
Worth to note that, if
methodX()
returns a List
and not another type of Collection
, it might be possible to return that list directly, instead of creating a new list and adding to that: .map(Supplier::get).filter(s -> !s.isEmpty()).findFirst().orElse(emptyList());
. Whether this is appropriate or not is not possible to determine from the question.– Magnilex
40 mins ago
By the way, do you know why you have to explicitly state the type
<Supplier<List<Object>>>
to the factory method because the compiler cannot infer the type itself? I had the same issue.– Ricola
28 mins ago
By the way, do you know why you have to explicitly state the type
<Supplier<List<Object>>>
to the factory method because the compiler cannot infer the type itself? I had the same issue.– Ricola
28 mins ago
@Ricola Without defining it explicitly, the compiler doesn't know the target type of lambda expressions. The alternative would have been to do it in two steps, explicitly declaring a
Stream<Supplier<List<Object>>>
as the type of the stream.– ernest_k
24 mins ago
@Ricola Without defining it explicitly, the compiler doesn't know the target type of lambda expressions. The alternative would have been to do it in two steps, explicitly declaring a
Stream<Supplier<List<Object>>>
as the type of the stream.– ernest_k
24 mins ago
add a comment |
You could try to check the return value of addAll
. It will return true
whenever the list has been modified, so try this:
List<Object> list = new ArrayList<>();
// ret unused, otherwise it doesn't compile
boolean ret = list.addAll(method1())
|| list.addAll(method2())
|| list.addAll(method3())
|| list.addAll(method4())
|| list.addAll(method5())
|| list.addAll(method6());
return list;
Because of lazy evaluation, the first addAll
operation that added at least one element will prevent the rest from bein called. I like the fact that "||" expresses the intent quite well.
1
one of the rare cases where one cares about the return value ofaddAll
. indeed very clever, efficient and readable! ;-).
– Aomine
11 mins ago
1
Agreed. I believe it can't get simpler or more readable than this.
– ernest_k
10 mins ago
add a comment |
You could try to check the return value of addAll
. It will return true
whenever the list has been modified, so try this:
List<Object> list = new ArrayList<>();
// ret unused, otherwise it doesn't compile
boolean ret = list.addAll(method1())
|| list.addAll(method2())
|| list.addAll(method3())
|| list.addAll(method4())
|| list.addAll(method5())
|| list.addAll(method6());
return list;
Because of lazy evaluation, the first addAll
operation that added at least one element will prevent the rest from bein called. I like the fact that "||" expresses the intent quite well.
1
one of the rare cases where one cares about the return value ofaddAll
. indeed very clever, efficient and readable! ;-).
– Aomine
11 mins ago
1
Agreed. I believe it can't get simpler or more readable than this.
– ernest_k
10 mins ago
add a comment |
You could try to check the return value of addAll
. It will return true
whenever the list has been modified, so try this:
List<Object> list = new ArrayList<>();
// ret unused, otherwise it doesn't compile
boolean ret = list.addAll(method1())
|| list.addAll(method2())
|| list.addAll(method3())
|| list.addAll(method4())
|| list.addAll(method5())
|| list.addAll(method6());
return list;
Because of lazy evaluation, the first addAll
operation that added at least one element will prevent the rest from bein called. I like the fact that "||" expresses the intent quite well.
You could try to check the return value of addAll
. It will return true
whenever the list has been modified, so try this:
List<Object> list = new ArrayList<>();
// ret unused, otherwise it doesn't compile
boolean ret = list.addAll(method1())
|| list.addAll(method2())
|| list.addAll(method3())
|| list.addAll(method4())
|| list.addAll(method5())
|| list.addAll(method6());
return list;
Because of lazy evaluation, the first addAll
operation that added at least one element will prevent the rest from bein called. I like the fact that "||" expresses the intent quite well.
edited 24 mins ago
answered 31 mins ago
Dorian Gray
815313
815313
1
one of the rare cases where one cares about the return value ofaddAll
. indeed very clever, efficient and readable! ;-).
– Aomine
11 mins ago
1
Agreed. I believe it can't get simpler or more readable than this.
– ernest_k
10 mins ago
add a comment |
1
one of the rare cases where one cares about the return value ofaddAll
. indeed very clever, efficient and readable! ;-).
– Aomine
11 mins ago
1
Agreed. I believe it can't get simpler or more readable than this.
– ernest_k
10 mins ago
1
1
one of the rare cases where one cares about the return value of
addAll
. indeed very clever, efficient and readable! ;-).– Aomine
11 mins ago
one of the rare cases where one cares about the return value of
addAll
. indeed very clever, efficient and readable! ;-).– Aomine
11 mins ago
1
1
Agreed. I believe it can't get simpler or more readable than this.
– ernest_k
10 mins ago
Agreed. I believe it can't get simpler or more readable than this.
– ernest_k
10 mins ago
add a comment |
A way of doing it without repeating yourself is to extract a method doing it for you:
private void addIfEmpty(List<Object> targetList, Supplier<Collection<?>> supplier) {
if (targetList.isEmpty()) {
targetList.addAll(supplier.get());
}
}
And then
List<Object> list = new ArrayList<>();
addIfEmpty(list, this::method1);
addIfEmpty(list, this::method2);
addIfEmpty(list, this::method3);
addIfEmpty(list, this::method4);
addIfEmpty(list, this::method5);
addIfEmpty(list, this::method6);
return list;
Or even use a for loop:
List<Supplier<Collection<?>>> suppliers = Arrays.asList(this::method1, this::method2, ...);
List<Object> list = new ArrayList<>();
suppliers.forEach(supplier -> this.addIfEmpty(list, supplier));
Now DRY is not the most important aspect. If you think your original code is easier to read and understand, then keep it like that.
You should rather name the methodaddIfEmpty
instead ofaddIfNotEmpty
– Ricola
35 mins ago
@Ricola good point, indeed.
– JB Nizet
23 mins ago
add a comment |
A way of doing it without repeating yourself is to extract a method doing it for you:
private void addIfEmpty(List<Object> targetList, Supplier<Collection<?>> supplier) {
if (targetList.isEmpty()) {
targetList.addAll(supplier.get());
}
}
And then
List<Object> list = new ArrayList<>();
addIfEmpty(list, this::method1);
addIfEmpty(list, this::method2);
addIfEmpty(list, this::method3);
addIfEmpty(list, this::method4);
addIfEmpty(list, this::method5);
addIfEmpty(list, this::method6);
return list;
Or even use a for loop:
List<Supplier<Collection<?>>> suppliers = Arrays.asList(this::method1, this::method2, ...);
List<Object> list = new ArrayList<>();
suppliers.forEach(supplier -> this.addIfEmpty(list, supplier));
Now DRY is not the most important aspect. If you think your original code is easier to read and understand, then keep it like that.
You should rather name the methodaddIfEmpty
instead ofaddIfNotEmpty
– Ricola
35 mins ago
@Ricola good point, indeed.
– JB Nizet
23 mins ago
add a comment |
A way of doing it without repeating yourself is to extract a method doing it for you:
private void addIfEmpty(List<Object> targetList, Supplier<Collection<?>> supplier) {
if (targetList.isEmpty()) {
targetList.addAll(supplier.get());
}
}
And then
List<Object> list = new ArrayList<>();
addIfEmpty(list, this::method1);
addIfEmpty(list, this::method2);
addIfEmpty(list, this::method3);
addIfEmpty(list, this::method4);
addIfEmpty(list, this::method5);
addIfEmpty(list, this::method6);
return list;
Or even use a for loop:
List<Supplier<Collection<?>>> suppliers = Arrays.asList(this::method1, this::method2, ...);
List<Object> list = new ArrayList<>();
suppliers.forEach(supplier -> this.addIfEmpty(list, supplier));
Now DRY is not the most important aspect. If you think your original code is easier to read and understand, then keep it like that.
A way of doing it without repeating yourself is to extract a method doing it for you:
private void addIfEmpty(List<Object> targetList, Supplier<Collection<?>> supplier) {
if (targetList.isEmpty()) {
targetList.addAll(supplier.get());
}
}
And then
List<Object> list = new ArrayList<>();
addIfEmpty(list, this::method1);
addIfEmpty(list, this::method2);
addIfEmpty(list, this::method3);
addIfEmpty(list, this::method4);
addIfEmpty(list, this::method5);
addIfEmpty(list, this::method6);
return list;
Or even use a for loop:
List<Supplier<Collection<?>>> suppliers = Arrays.asList(this::method1, this::method2, ...);
List<Object> list = new ArrayList<>();
suppliers.forEach(supplier -> this.addIfEmpty(list, supplier));
Now DRY is not the most important aspect. If you think your original code is easier to read and understand, then keep it like that.
edited 24 mins ago
answered 1 hour ago
JB Nizet
534k51860993
534k51860993
You should rather name the methodaddIfEmpty
instead ofaddIfNotEmpty
– Ricola
35 mins ago
@Ricola good point, indeed.
– JB Nizet
23 mins ago
add a comment |
You should rather name the methodaddIfEmpty
instead ofaddIfNotEmpty
– Ricola
35 mins ago
@Ricola good point, indeed.
– JB Nizet
23 mins ago
You should rather name the method
addIfEmpty
instead of addIfNotEmpty
– Ricola
35 mins ago
You should rather name the method
addIfEmpty
instead of addIfNotEmpty
– Ricola
35 mins ago
@Ricola good point, indeed.
– JB Nizet
23 mins ago
@Ricola good point, indeed.
– JB Nizet
23 mins ago
add a comment |
You could create a method as such:
public static List<Object> lazyVersion(Supplier<List<Object>>... suppliers){
return Arrays.stream(suppliers)
.map(Supplier::get)
.filter(s -> !s.isEmpty()) // or .filter(Predicate.not(List::isEmpty)) as of JDK11
.findFirst()
.orElseGet(Collections::emptyList);
}
and then call it as follows:
lazyVersion(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6());
method name for illustration purposes only.
add a comment |
You could create a method as such:
public static List<Object> lazyVersion(Supplier<List<Object>>... suppliers){
return Arrays.stream(suppliers)
.map(Supplier::get)
.filter(s -> !s.isEmpty()) // or .filter(Predicate.not(List::isEmpty)) as of JDK11
.findFirst()
.orElseGet(Collections::emptyList);
}
and then call it as follows:
lazyVersion(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6());
method name for illustration purposes only.
add a comment |
You could create a method as such:
public static List<Object> lazyVersion(Supplier<List<Object>>... suppliers){
return Arrays.stream(suppliers)
.map(Supplier::get)
.filter(s -> !s.isEmpty()) // or .filter(Predicate.not(List::isEmpty)) as of JDK11
.findFirst()
.orElseGet(Collections::emptyList);
}
and then call it as follows:
lazyVersion(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6());
method name for illustration purposes only.
You could create a method as such:
public static List<Object> lazyVersion(Supplier<List<Object>>... suppliers){
return Arrays.stream(suppliers)
.map(Supplier::get)
.filter(s -> !s.isEmpty()) // or .filter(Predicate.not(List::isEmpty)) as of JDK11
.findFirst()
.orElseGet(Collections::emptyList);
}
and then call it as follows:
lazyVersion(() -> method1(),
() -> method2(),
() -> method3(),
() -> method4(),
() -> method5(),
() -> method6());
method name for illustration purposes only.
edited 18 mins ago
answered 32 mins ago
Aomine
39.2k73669
39.2k73669
add a comment |
add a comment |
You could make your code nicer by creating the method
public void addAllIfEmpty(List<Object> list, Supplier<List<Object>> method){
if(list.isEmpty()){
list.addAll(method.get());
}
}
Then you can use it like this (I assumed your methods are not static methods, if they are you need to reference them using ClassName::method1
)
List<Object> list = new ArrayList<>();
list.addAll(method1());
addAllIfEmpty(list, this::method2);
addAllIfEmpty(list, this::method3);
addAllIfEmpty(list, this::method4);
addAllIfEmpty(list, this::method5);
addAllIfEmpty(list, this::method6);
return list;
If you really want to use a Stream, you could do this
Stream.<Supplier<List<Object>>>of(this::method1, this::method2, this::method3, this::method4, this::method5, this::method6)
.collect(ArrayList::new, this::addAllIfEmpty, ArrayList::addAll);
IMO it makes it more complicated, depending on how your methods are referenced, it might be better to use a loop
add a comment |
You could make your code nicer by creating the method
public void addAllIfEmpty(List<Object> list, Supplier<List<Object>> method){
if(list.isEmpty()){
list.addAll(method.get());
}
}
Then you can use it like this (I assumed your methods are not static methods, if they are you need to reference them using ClassName::method1
)
List<Object> list = new ArrayList<>();
list.addAll(method1());
addAllIfEmpty(list, this::method2);
addAllIfEmpty(list, this::method3);
addAllIfEmpty(list, this::method4);
addAllIfEmpty(list, this::method5);
addAllIfEmpty(list, this::method6);
return list;
If you really want to use a Stream, you could do this
Stream.<Supplier<List<Object>>>of(this::method1, this::method2, this::method3, this::method4, this::method5, this::method6)
.collect(ArrayList::new, this::addAllIfEmpty, ArrayList::addAll);
IMO it makes it more complicated, depending on how your methods are referenced, it might be better to use a loop
add a comment |
You could make your code nicer by creating the method
public void addAllIfEmpty(List<Object> list, Supplier<List<Object>> method){
if(list.isEmpty()){
list.addAll(method.get());
}
}
Then you can use it like this (I assumed your methods are not static methods, if they are you need to reference them using ClassName::method1
)
List<Object> list = new ArrayList<>();
list.addAll(method1());
addAllIfEmpty(list, this::method2);
addAllIfEmpty(list, this::method3);
addAllIfEmpty(list, this::method4);
addAllIfEmpty(list, this::method5);
addAllIfEmpty(list, this::method6);
return list;
If you really want to use a Stream, you could do this
Stream.<Supplier<List<Object>>>of(this::method1, this::method2, this::method3, this::method4, this::method5, this::method6)
.collect(ArrayList::new, this::addAllIfEmpty, ArrayList::addAll);
IMO it makes it more complicated, depending on how your methods are referenced, it might be better to use a loop
You could make your code nicer by creating the method
public void addAllIfEmpty(List<Object> list, Supplier<List<Object>> method){
if(list.isEmpty()){
list.addAll(method.get());
}
}
Then you can use it like this (I assumed your methods are not static methods, if they are you need to reference them using ClassName::method1
)
List<Object> list = new ArrayList<>();
list.addAll(method1());
addAllIfEmpty(list, this::method2);
addAllIfEmpty(list, this::method3);
addAllIfEmpty(list, this::method4);
addAllIfEmpty(list, this::method5);
addAllIfEmpty(list, this::method6);
return list;
If you really want to use a Stream, you could do this
Stream.<Supplier<List<Object>>>of(this::method1, this::method2, this::method3, this::method4, this::method5, this::method6)
.collect(ArrayList::new, this::addAllIfEmpty, ArrayList::addAll);
IMO it makes it more complicated, depending on how your methods are referenced, it might be better to use a loop
edited 10 mins ago
answered 57 mins ago
Ricola
16510
16510
add a comment |
add a comment |
Java 8 streams weren't designed to support this kind of operation. From the jdk:
A stream should be operated on (invoking an intermediate or terminal stream operation) only once. This rules out, for example, "forked" streams, where the same source feeds two or more pipelines, or multiple traversals of the same stream.
If you can store it in memory you can use Collectors.partitioningBy
if you have just two types and go by with a Map<Boolean, List>
. Otherwise use Collectors.groupingBy
.
add a comment |
Java 8 streams weren't designed to support this kind of operation. From the jdk:
A stream should be operated on (invoking an intermediate or terminal stream operation) only once. This rules out, for example, "forked" streams, where the same source feeds two or more pipelines, or multiple traversals of the same stream.
If you can store it in memory you can use Collectors.partitioningBy
if you have just two types and go by with a Map<Boolean, List>
. Otherwise use Collectors.groupingBy
.
add a comment |
Java 8 streams weren't designed to support this kind of operation. From the jdk:
A stream should be operated on (invoking an intermediate or terminal stream operation) only once. This rules out, for example, "forked" streams, where the same source feeds two or more pipelines, or multiple traversals of the same stream.
If you can store it in memory you can use Collectors.partitioningBy
if you have just two types and go by with a Map<Boolean, List>
. Otherwise use Collectors.groupingBy
.
Java 8 streams weren't designed to support this kind of operation. From the jdk:
A stream should be operated on (invoking an intermediate or terminal stream operation) only once. This rules out, for example, "forked" streams, where the same source feeds two or more pipelines, or multiple traversals of the same stream.
If you can store it in memory you can use Collectors.partitioningBy
if you have just two types and go by with a Map<Boolean, List>
. Otherwise use Collectors.groupingBy
.
answered 1 hour ago
Sagar P. Ghagare
5218
5218
add a comment |
add a comment |
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.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- 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%2f53957780%2fjava-8-list-processing-add-elements-conditionally%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
1
I don't think there's a faster way to do it.
– gbandres
1 hour ago