You can write, given for instance a List<Boolean>:
if (!list.stream().allMatch(x -> x)) {
// not every member is true
}
Or:
if (list.stream().anyMatch(x -> !x)) {
// at least one member is false
}
If you have an array of booleans, then use Arrays.stream() to obtain a stream out of it instead.
More generally, for a Stream providing elements of (generic) type X, you have to provide a Predicate<? super X> to .{all,any}Match() (either a "full" predicate, or a lambda, or a method reference -- many things go). The return value of these methods are self explanatory -- I think.
Now, to count elements which obey a certain predicate, you have .count(), which you can combine with .filter() -- which also takes (whatever is) a Predicate as an argument. For instance checking if you have more than 2 elements in a List<String> whose length is greater than 5 you'd do:
if (list.stream().filter(s -> s.length() > 5).count() > 2L) {
// Yup...
}
Answer from fge on Stack OverflowYou can write, given for instance a List<Boolean>:
if (!list.stream().allMatch(x -> x)) {
// not every member is true
}
Or:
if (list.stream().anyMatch(x -> !x)) {
// at least one member is false
}
If you have an array of booleans, then use Arrays.stream() to obtain a stream out of it instead.
More generally, for a Stream providing elements of (generic) type X, you have to provide a Predicate<? super X> to .{all,any}Match() (either a "full" predicate, or a lambda, or a method reference -- many things go). The return value of these methods are self explanatory -- I think.
Now, to count elements which obey a certain predicate, you have .count(), which you can combine with .filter() -- which also takes (whatever is) a Predicate as an argument. For instance checking if you have more than 2 elements in a List<String> whose length is greater than 5 you'd do:
if (list.stream().filter(s -> s.length() > 5).count() > 2L) {
// Yup...
}
Your problem
Your current problem is that you use directly a lambda expression. Lambdas are instances of functional interfaces. Your lambda does not have the boolean type, that's why your if does not accept it.
This special case's solution
You can use a stream from your collections of booleans here.
if (bools.stream().allMatch((Boolean b)->b)) {
// do something
}
It is actually much more powerful than this, but this does the trick I believe.
General hint
Basically, since you want an if condition, you want a boolean result.
Since your result depends on a collection, you can use Java 8 streams on collections.
Java 8 streams allow you to do many operations on a collection, and finish with a terminal operation. You can do whatever complicated stuff you want with Stream's non-terminal operations. In the end you need one of 2 things:
- use a terminal operation that returns a
boolean(such asallMatch,anyMatch...), and you're done - use any terminal operation, but use it in a
booleanexpression, such asmyStream.filter(...).limit(...).count() > 2
You should have a look at your possibilities in this Stream documentation or this one.
How to perform nested 'if' statements using Java 8/lambda? - Stack Overflow
if statement - Use Java lambda instead of 'if else' - Stack Overflow
use if-else statement in java-8 lambda expression - Stack Overflow
How do you use conditions in lambda expression in java 8? - Stack Overflow
Videos
The essential observation here is that your problem involves a non-isomorphic transformation: a single input element may map to zero, one, or two output elements. Whenever you notice this, you should immediately start looking for a solution which involves flatMap instead of map because that's the only way to achieve such a general transformation. In your particular case you can first apply filter for a one-to-zero element mapping, then flatMap for one-to-two mapping:
List<Integer> result =
IntStream.rangeClosed(1, 10)
.filter(i -> 10 % i == 0)
.flatMap(i -> i == 5 ? IntStream.of(i) : IntStream.of(i, 10 / i))
.boxed()
.collect(toList());
(assuming import static java.util.stream.Collectors.toList)
You could declare a body for a lambda. For example:
Runnable run = () -> System.out.println("Hey");
Could be
Runnable run = () -> {
System.out.println("Hey");
};
Within that body, you can create nested statements:
Runnable run = () -> {
int num = 5;
if(num == 5) {
System.out.println("Hey");
}
};
As it almost but not really matches Optional, maybe you might reconsider the logic:
Java 8 has a limited expressiveness:
Optional<Elem> element = ...
element.ifPresent(el -> System.out.println("Present " + el);
System.out.println(element.orElse(DEFAULT_ELEM));
Here the map might restrict the view on the element:
element.map(el -> el.mySpecialView()).ifPresent(System.out::println);
Java 9:
element.ifPresentOrElse(el -> System.out.println("Present " + el,
() -> System.out.println("Not present"));
In general the two branches are asymmetric.
It's called a 'fluent interface'. Simply change the return type and return this; to allow you to chain the methods:
public MyClass ifExist(Consumer<Element> consumer) {
if (exist()) {
consumer.accept(this);
}
return this;
}
public MyClass ifNotExist(Consumer<Element> consumer) {
if (!exist()) {
consumer.accept(this);
}
return this;
}
You could get a bit fancier and return an intermediate type:
interface Else<T>
{
public void otherwise(Consumer<T> consumer); // 'else' is a keyword
}
class DefaultElse<T> implements Else<T>
{
private final T item;
DefaultElse(final T item) { this.item = item; }
public void otherwise(Consumer<T> consumer)
{
consumer.accept(item);
}
}
class NoopElse<T> implements Else<T>
{
public void otherwise(Consumer<T> consumer) { }
}
public Else<MyClass> ifExist(Consumer<Element> consumer) {
if (exist()) {
consumer.accept(this);
return new NoopElse<>();
}
return new DefaultElse<>(this);
}
Sample usage:
element.ifExist(el -> {
//do something
})
.otherwise(el -> {
//do something else
});
As a stream call chain is complex make two streams - avoiding the conditional branches.
String ncourseIds = equivalentCourses.stream()
.filter(equivalentCourse -> equivalentCourse.getNcourse() != null)
.map(EquivalentCourse::getNcourse)
.map(x -> String.valueOf(x.getId()))
.collect(Collectors.joining(", "));
String pastCourseIds = equivalentCourses.stream()
.filter(equivalentCourse -> equivalentCourse.getNcourse() == null
&& equivalentCourse.getPastCourse() != null)
.map(EquivalentCourse::getPastCourse)
.map(x -> String.valueOf(x.getId()))
.collect(Collectors.joining(", "));
This also is code focusing on the resulting two strings, with an efficient joining.
By the way, if this is for an SQL string, you may use a PreparedStatement with an Array.
Embellishment as commented by @Holger:
String ncourseIds = equivalentCourses.stream()
.map(EquivalentCourse::getNcourse)
.filter(Objects::nonNull)
.map(NCourse::getId)
.map(String::valueOf)
.collect(Collectors.joining(", "));
String pastCourseIds = equivalentCourses.stream()
.filter(equivalentCourse -> equivalentCourse.getNcourse() == null)
.map(EquivalentCourse::getPastCourse)
.filter(Objects::nonNull)
.map(EquivalentCourse::getPastCourse)
.map(PastCourse::getId)
.map(String::valueOf)
.collect(Collectors.joining(", "));
You could group by condition and then remap:
public void booleanGrouping() throws Exception {
List<String> strings = new ArrayList<>();
strings.add("ala");
strings.add("ela");
strings.add("jan");
strings.stream()
.collect(
Collectors.groupingBy(s -> s.endsWith("a")) // using function Obj -> Bool not predicate
).entrySet()
.stream()
.collect(
Collectors.toMap(
e -> e.getKey() ? "Present" : "Past",
e -> e.getValue().stream().collect(Collectors.joining(""))
)
);
}
First stream group by condition, you should use equivalentCourse.getNcourse() != null second remap collections from value to string. You could introduce:
enum PresentPast{
Present, Past
PresentPast is(boolean v){
return v ? Present : Past
}
}
and change e -> e.getKey() ? "Present" : "Past" to enum based solution.
Edit:
Solution for else if:
public Map<Classifier, String> booleanGrouping() throws Exception {
List<String> strings = new ArrayList<>();
strings.add("ala");
strings.add("ela");
strings.add("jan");
// our ifs:
/*
if(!string.endsWith("n")){
}else if(string.startsWith("e")){}
final map should contains two elements
endsWithN -> ["jan"]
startsWithE -> ["ela"]
NOT_MATCH -> ["ala"]
*/
return strings.stream()
.collect(
Collectors.groupingBy(Classifier::apply) // using function Obj -> Bool not predicate
).entrySet()
.stream()
.collect(
Collectors.toMap(
e -> e.getKey(),
e -> e.getValue().stream().collect(Collectors.joining(""))
)
);
}
enum Classifier implements Predicate<String> {
ENDS_WITH_N {
@Override
public boolean test(String s) {
return s.endsWith("n");
}
},
STARTS_WITH_E {
@Override
public boolean test(String s) {
return s.startsWith("e");
}
}, NOT_MATCH {
@Override
public boolean test(String s) {
return false;
}
};
public static Classifier apply(String s) {
return Arrays.stream(Classifier.values())
.filter(c -> c.test(s))
.findFirst().orElse(NOT_MATCH);
}
}
So my question is how can i write a lambda expression that covers this function...
You either write a lambda with a block body ({}) (what I call a "verbose lambda") and use return:
MathInteface f1 = (int x) -> {
if (x % 2 == 0) {
return x / 2;
}
return (x + 1) / 2;
};
or you use the conditional operator:
MathInteface f1 = (int x) -> (x % 2 == 0) ? x / 2 : (x + 1) / 2;
(or both).
More details in the lambda tutorial.
For that particular function, a ternary would be possible.
(int x) -> x % 2 == 0 ? x/2 : (x+1)/2;
Otherwise, make a block
(int x) -> {
// if... else
}
Inside of which, you return the value
If/else or even switch are not the "good OO design" answer. Neither are lambdas. Retrieving the status from somewhere, to make then a decision based on that - that is procedural programming; not OO.
You see, what you actually have in front of you - is a state machine. You have different states; and the point is: if your "thing" is in state A; then you want to do something ( invoke handleA() ). If your are in state B; you want to do something too ( like invoke handleB() ).
So, what you actually have is:
abstract class State {
abstract void doIt();
...
StateA extends State {
@Override
void doIt() { handleA(); }
So, from the client side, you just call doIt() on same object of class State.
Thus: if you are really interested in improving your code base, learn how to use polymorphism to get rid of your if/else/switch statements.
You can watch this video to get an idea what I am talking about.
Maybe I hadn't fully explained my problem, but my colleague proposed another solution that I really like. He suggested I make the if-else block a java.util.Supplier, and invoke it in the Entity class where I need it.
So my code went from this block of logic sprinkled everywhere:
public class ServiceImpl {
...
if (entity.getStatus) == 'A' then
finalStatus = handleA();
else if (entity.getStatus() == 'B') then
finalStatus = handleB();
else
finalStatus = handleEverythingElse();
...
}
To this nicely compacted form:
public class ServiceImpl {
finalStatus = entity.getFinalStatus(this::handleStatus);
public int handleStatus() {
return dao.getStatus();
}
}
With the implementation in my Entity class:
public class Entity {
public int handleStatus(Supplier<Integer> s) {
int finalStatus;
if (status) == 'A' then
finalStatus = handleA();
else if (status() == 'B') then
finalStatus = handleB();
else
finalStatus = supplier.get();
return status;
}
}
I hope this make sense...