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 java-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 java-stream
What do the methods return as object, exactly?
– Eric Duminil
yesterday
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 java-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 java-stream
java collections java-8 java-stream
edited 2 days ago
Aomine
39.4k73669
39.4k73669
asked 2 days ago
ionut
17517
17517
What do the methods return as object, exactly?
– Eric Duminil
yesterday
add a comment |
What do the methods return as object, exactly?
– Eric Duminil
yesterday
What do the methods return as object, exactly?
– Eric Duminil
yesterday
What do the methods return as object, exactly?
– Eric Duminil
yesterday
add a comment |
5 Answers
5
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);
5
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
2 days 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
2 days ago
4
You can also usethis::method1
to reduce ther amount of boilerplate
– Boris the Spider
2 days ago
1
@BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
– ernest_k
2 days ago
3
@SebastiaanvandenBroek certainly a matter of taste - I can't agree with your assessment. The code in the question has the same logic copy/pasted 5 times. The code above has no such repetition - to me this makes the functional logic rather superior.
– Boris the Spider
2 days ago
|
show 4 more comments
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.
4
one of the rare cases where one cares about the return value ofaddAll
. indeed very clever, efficient and readable! ;-).
– Aomine
2 days ago
4
@Aomine I don't find the misuse of boolean expressions to mimic ordered executions readable and maintainable at all. The next best bloke might reorder the expressions because "it's an OR expression, the order shouldn't matter" and boom you have a hard to find bug. The necessary comment about having a variable just for it to compile imho is a hint of bad design as well. So while this answers the question somehow, I wouldn't recommend to use this in production code.
– Darkwing
2 days ago
3
@DorianGray The methods hopefully won't be named method1...method6 in the code! That says nothing about what they do. And yes pragmatically there is a difference in the order, but logically it does not matter. This is why you should be really careful when assuming the execution order just because you know how your compiler/jvm will translate/execute the expression. If you are optimising down to the last bit, sure order it the way it makes most sense, but don't have business logic rely on it unless there is a really big benefit/demand to do so.
– Darkwing
2 days ago
5
@Darkwing It's not compiler/jvm specific behaviour, language specification itsself defines that behaviour of lazy evaluation. I'm not assuming anything, I know how the language is defined. The behaviour is widely known, e.g. lazy evaluation used in order to place a null check in the first place, dereferencing it afterwards. At least you have a very strange definition of assuming something that is defined in the language specification. The word assuming implies a certain uncertainity about the actual behaviour. If you know for sure what you are doing, you don't assume it.
– Dorian Gray
2 days ago
9
@Darkwing but... the order of OR does matter! A logical OR is a short-circuit operation and is used extensively exactly because of that.
– Sebastiaan van den Broek
2 days ago
|
show 12 more comments
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
2 days ago
@Ricola good point, indeed.
– JB Nizet
2 days 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 |
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
5 Answers
5
active
oldest
votes
5 Answers
5
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);
5
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
2 days 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
2 days ago
4
You can also usethis::method1
to reduce ther amount of boilerplate
– Boris the Spider
2 days ago
1
@BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
– ernest_k
2 days ago
3
@SebastiaanvandenBroek certainly a matter of taste - I can't agree with your assessment. The code in the question has the same logic copy/pasted 5 times. The code above has no such repetition - to me this makes the functional logic rather superior.
– Boris the Spider
2 days ago
|
show 4 more comments
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);
5
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
2 days 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
2 days ago
4
You can also usethis::method1
to reduce ther amount of boilerplate
– Boris the Spider
2 days ago
1
@BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
– ernest_k
2 days ago
3
@SebastiaanvandenBroek certainly a matter of taste - I can't agree with your assessment. The code in the question has the same logic copy/pasted 5 times. The code above has no such repetition - to me this makes the functional logic rather superior.
– Boris the Spider
2 days ago
|
show 4 more comments
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 2 days ago
Aomine
39.4k73669
39.4k73669
answered 2 days ago
ernest_k
19.9k42043
19.9k42043
5
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
2 days 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
2 days ago
4
You can also usethis::method1
to reduce ther amount of boilerplate
– Boris the Spider
2 days ago
1
@BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
– ernest_k
2 days ago
3
@SebastiaanvandenBroek certainly a matter of taste - I can't agree with your assessment. The code in the question has the same logic copy/pasted 5 times. The code above has no such repetition - to me this makes the functional logic rather superior.
– Boris the Spider
2 days ago
|
show 4 more comments
5
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
2 days 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
2 days ago
4
You can also usethis::method1
to reduce ther amount of boilerplate
– Boris the Spider
2 days ago
1
@BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
– ernest_k
2 days ago
3
@SebastiaanvandenBroek certainly a matter of taste - I can't agree with your assessment. The code in the question has the same logic copy/pasted 5 times. The code above has no such repetition - to me this makes the functional logic rather superior.
– Boris the Spider
2 days ago
5
5
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
2 days 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
2 days 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
2 days 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
2 days ago
4
4
You can also use
this::method1
to reduce ther amount of boilerplate– Boris the Spider
2 days ago
You can also use
this::method1
to reduce ther amount of boilerplate– Boris the Spider
2 days ago
1
1
@BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
– ernest_k
2 days ago
@BoristheSpider Agreed (just didn't want to assume that the code is in an instance method)
– ernest_k
2 days ago
3
3
@SebastiaanvandenBroek certainly a matter of taste - I can't agree with your assessment. The code in the question has the same logic copy/pasted 5 times. The code above has no such repetition - to me this makes the functional logic rather superior.
– Boris the Spider
2 days ago
@SebastiaanvandenBroek certainly a matter of taste - I can't agree with your assessment. The code in the question has the same logic copy/pasted 5 times. The code above has no such repetition - to me this makes the functional logic rather superior.
– Boris the Spider
2 days ago
|
show 4 more comments
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.
4
one of the rare cases where one cares about the return value ofaddAll
. indeed very clever, efficient and readable! ;-).
– Aomine
2 days ago
4
@Aomine I don't find the misuse of boolean expressions to mimic ordered executions readable and maintainable at all. The next best bloke might reorder the expressions because "it's an OR expression, the order shouldn't matter" and boom you have a hard to find bug. The necessary comment about having a variable just for it to compile imho is a hint of bad design as well. So while this answers the question somehow, I wouldn't recommend to use this in production code.
– Darkwing
2 days ago
3
@DorianGray The methods hopefully won't be named method1...method6 in the code! That says nothing about what they do. And yes pragmatically there is a difference in the order, but logically it does not matter. This is why you should be really careful when assuming the execution order just because you know how your compiler/jvm will translate/execute the expression. If you are optimising down to the last bit, sure order it the way it makes most sense, but don't have business logic rely on it unless there is a really big benefit/demand to do so.
– Darkwing
2 days ago
5
@Darkwing It's not compiler/jvm specific behaviour, language specification itsself defines that behaviour of lazy evaluation. I'm not assuming anything, I know how the language is defined. The behaviour is widely known, e.g. lazy evaluation used in order to place a null check in the first place, dereferencing it afterwards. At least you have a very strange definition of assuming something that is defined in the language specification. The word assuming implies a certain uncertainity about the actual behaviour. If you know for sure what you are doing, you don't assume it.
– Dorian Gray
2 days ago
9
@Darkwing but... the order of OR does matter! A logical OR is a short-circuit operation and is used extensively exactly because of that.
– Sebastiaan van den Broek
2 days ago
|
show 12 more comments
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.
4
one of the rare cases where one cares about the return value ofaddAll
. indeed very clever, efficient and readable! ;-).
– Aomine
2 days ago
4
@Aomine I don't find the misuse of boolean expressions to mimic ordered executions readable and maintainable at all. The next best bloke might reorder the expressions because "it's an OR expression, the order shouldn't matter" and boom you have a hard to find bug. The necessary comment about having a variable just for it to compile imho is a hint of bad design as well. So while this answers the question somehow, I wouldn't recommend to use this in production code.
– Darkwing
2 days ago
3
@DorianGray The methods hopefully won't be named method1...method6 in the code! That says nothing about what they do. And yes pragmatically there is a difference in the order, but logically it does not matter. This is why you should be really careful when assuming the execution order just because you know how your compiler/jvm will translate/execute the expression. If you are optimising down to the last bit, sure order it the way it makes most sense, but don't have business logic rely on it unless there is a really big benefit/demand to do so.
– Darkwing
2 days ago
5
@Darkwing It's not compiler/jvm specific behaviour, language specification itsself defines that behaviour of lazy evaluation. I'm not assuming anything, I know how the language is defined. The behaviour is widely known, e.g. lazy evaluation used in order to place a null check in the first place, dereferencing it afterwards. At least you have a very strange definition of assuming something that is defined in the language specification. The word assuming implies a certain uncertainity about the actual behaviour. If you know for sure what you are doing, you don't assume it.
– Dorian Gray
2 days ago
9
@Darkwing but... the order of OR does matter! A logical OR is a short-circuit operation and is used extensively exactly because of that.
– Sebastiaan van den Broek
2 days ago
|
show 12 more comments
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 2 days ago
answered 2 days ago
Dorian Gray
1,205415
1,205415
4
one of the rare cases where one cares about the return value ofaddAll
. indeed very clever, efficient and readable! ;-).
– Aomine
2 days ago
4
@Aomine I don't find the misuse of boolean expressions to mimic ordered executions readable and maintainable at all. The next best bloke might reorder the expressions because "it's an OR expression, the order shouldn't matter" and boom you have a hard to find bug. The necessary comment about having a variable just for it to compile imho is a hint of bad design as well. So while this answers the question somehow, I wouldn't recommend to use this in production code.
– Darkwing
2 days ago
3
@DorianGray The methods hopefully won't be named method1...method6 in the code! That says nothing about what they do. And yes pragmatically there is a difference in the order, but logically it does not matter. This is why you should be really careful when assuming the execution order just because you know how your compiler/jvm will translate/execute the expression. If you are optimising down to the last bit, sure order it the way it makes most sense, but don't have business logic rely on it unless there is a really big benefit/demand to do so.
– Darkwing
2 days ago
5
@Darkwing It's not compiler/jvm specific behaviour, language specification itsself defines that behaviour of lazy evaluation. I'm not assuming anything, I know how the language is defined. The behaviour is widely known, e.g. lazy evaluation used in order to place a null check in the first place, dereferencing it afterwards. At least you have a very strange definition of assuming something that is defined in the language specification. The word assuming implies a certain uncertainity about the actual behaviour. If you know for sure what you are doing, you don't assume it.
– Dorian Gray
2 days ago
9
@Darkwing but... the order of OR does matter! A logical OR is a short-circuit operation and is used extensively exactly because of that.
– Sebastiaan van den Broek
2 days ago
|
show 12 more comments
4
one of the rare cases where one cares about the return value ofaddAll
. indeed very clever, efficient and readable! ;-).
– Aomine
2 days ago
4
@Aomine I don't find the misuse of boolean expressions to mimic ordered executions readable and maintainable at all. The next best bloke might reorder the expressions because "it's an OR expression, the order shouldn't matter" and boom you have a hard to find bug. The necessary comment about having a variable just for it to compile imho is a hint of bad design as well. So while this answers the question somehow, I wouldn't recommend to use this in production code.
– Darkwing
2 days ago
3
@DorianGray The methods hopefully won't be named method1...method6 in the code! That says nothing about what they do. And yes pragmatically there is a difference in the order, but logically it does not matter. This is why you should be really careful when assuming the execution order just because you know how your compiler/jvm will translate/execute the expression. If you are optimising down to the last bit, sure order it the way it makes most sense, but don't have business logic rely on it unless there is a really big benefit/demand to do so.
– Darkwing
2 days ago
5
@Darkwing It's not compiler/jvm specific behaviour, language specification itsself defines that behaviour of lazy evaluation. I'm not assuming anything, I know how the language is defined. The behaviour is widely known, e.g. lazy evaluation used in order to place a null check in the first place, dereferencing it afterwards. At least you have a very strange definition of assuming something that is defined in the language specification. The word assuming implies a certain uncertainity about the actual behaviour. If you know for sure what you are doing, you don't assume it.
– Dorian Gray
2 days ago
9
@Darkwing but... the order of OR does matter! A logical OR is a short-circuit operation and is used extensively exactly because of that.
– Sebastiaan van den Broek
2 days ago
4
4
one of the rare cases where one cares about the return value of
addAll
. indeed very clever, efficient and readable! ;-).– Aomine
2 days ago
one of the rare cases where one cares about the return value of
addAll
. indeed very clever, efficient and readable! ;-).– Aomine
2 days ago
4
4
@Aomine I don't find the misuse of boolean expressions to mimic ordered executions readable and maintainable at all. The next best bloke might reorder the expressions because "it's an OR expression, the order shouldn't matter" and boom you have a hard to find bug. The necessary comment about having a variable just for it to compile imho is a hint of bad design as well. So while this answers the question somehow, I wouldn't recommend to use this in production code.
– Darkwing
2 days ago
@Aomine I don't find the misuse of boolean expressions to mimic ordered executions readable and maintainable at all. The next best bloke might reorder the expressions because "it's an OR expression, the order shouldn't matter" and boom you have a hard to find bug. The necessary comment about having a variable just for it to compile imho is a hint of bad design as well. So while this answers the question somehow, I wouldn't recommend to use this in production code.
– Darkwing
2 days ago
3
3
@DorianGray The methods hopefully won't be named method1...method6 in the code! That says nothing about what they do. And yes pragmatically there is a difference in the order, but logically it does not matter. This is why you should be really careful when assuming the execution order just because you know how your compiler/jvm will translate/execute the expression. If you are optimising down to the last bit, sure order it the way it makes most sense, but don't have business logic rely on it unless there is a really big benefit/demand to do so.
– Darkwing
2 days ago
@DorianGray The methods hopefully won't be named method1...method6 in the code! That says nothing about what they do. And yes pragmatically there is a difference in the order, but logically it does not matter. This is why you should be really careful when assuming the execution order just because you know how your compiler/jvm will translate/execute the expression. If you are optimising down to the last bit, sure order it the way it makes most sense, but don't have business logic rely on it unless there is a really big benefit/demand to do so.
– Darkwing
2 days ago
5
5
@Darkwing It's not compiler/jvm specific behaviour, language specification itsself defines that behaviour of lazy evaluation. I'm not assuming anything, I know how the language is defined. The behaviour is widely known, e.g. lazy evaluation used in order to place a null check in the first place, dereferencing it afterwards. At least you have a very strange definition of assuming something that is defined in the language specification. The word assuming implies a certain uncertainity about the actual behaviour. If you know for sure what you are doing, you don't assume it.
– Dorian Gray
2 days ago
@Darkwing It's not compiler/jvm specific behaviour, language specification itsself defines that behaviour of lazy evaluation. I'm not assuming anything, I know how the language is defined. The behaviour is widely known, e.g. lazy evaluation used in order to place a null check in the first place, dereferencing it afterwards. At least you have a very strange definition of assuming something that is defined in the language specification. The word assuming implies a certain uncertainity about the actual behaviour. If you know for sure what you are doing, you don't assume it.
– Dorian Gray
2 days ago
9
9
@Darkwing but... the order of OR does matter! A logical OR is a short-circuit operation and is used extensively exactly because of that.
– Sebastiaan van den Broek
2 days ago
@Darkwing but... the order of OR does matter! A logical OR is a short-circuit operation and is used extensively exactly because of that.
– Sebastiaan van den Broek
2 days ago
|
show 12 more comments
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
2 days ago
@Ricola good point, indeed.
– JB Nizet
2 days 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
2 days ago
@Ricola good point, indeed.
– JB Nizet
2 days 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 2 days ago
answered 2 days ago
JB Nizet
534k52860994
534k52860994
You should rather name the methodaddIfEmpty
instead ofaddIfNotEmpty
– Ricola
2 days ago
@Ricola good point, indeed.
– JB Nizet
2 days ago
add a comment |
You should rather name the methodaddIfEmpty
instead ofaddIfNotEmpty
– Ricola
2 days ago
@Ricola good point, indeed.
– JB Nizet
2 days ago
You should rather name the method
addIfEmpty
instead of addIfNotEmpty
– Ricola
2 days ago
You should rather name the method
addIfEmpty
instead of addIfNotEmpty
– Ricola
2 days ago
@Ricola good point, indeed.
– JB Nizet
2 days ago
@Ricola good point, indeed.
– JB Nizet
2 days 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 2 days ago
answered 2 days ago
Aomine
39.4k73669
39.4k73669
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 2 days ago
answered 2 days ago
Ricola
400111
400111
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
What do the methods return as object, exactly?
– Eric Duminil
yesterday