Convert cycle to lambda expression - java

List<Mt4Strategy> openStrategies = ...
OrderType sample = openStrategies.get(0).calculate().getOrderType();
boolean success = true;
for (int i = 1; i < openStrategies.size(); i++) {
Mt4Action calculate = openStrategies.get(i).calculate();
if (calculate.getOrderType() != sample) {
success = false;
break;
}
}
OrderType is an enum.
I don't know what the first element contains and as a result am forced to make openStrategies.get(0).... I want to get rid of this get(0), but how?
I tried to use lambda like this:
OrderType sample = openStrategies.get(0).calculate().getOrderType();
boolean success = IntStream.range(1, openStrategies.size()).mapToObj(i ->
openStrategies.get(i).calculate()).noneMatch(calculate ->
calculate.getOrderType() != sample);
It's a good start but does not resolve my get(0).
Can using a lambda get rid of it? How I can write this to check success without get(0)? Lambda solution in priority something similar to last case .noneMatch.

You apparently want to determine whether all the input list elements have the same order type. A stream ought to make this pretty simple. For example,
boolean success = openStrategies.stream()
.map(s -> s.calculate().getOrderType())
.distinct()
.limit(2)
.count() == 1;
Note here the distinctness comparisons are done with equals rather than ==. If you really need ==, it's more difficult.
This checks for exactly one value in the list. If the input can be empty and you want the result to be true in that case, change == 1 to <= 1.
The limit(2) isn't needed for correctness but allows the search to stop as soon as a second distinct value is found, so it's more efficient.
There are other ways to do this.
Responding to comment
There are various hacky ways you could get the common value without calling .get(0), but none that would be clearer (at least that I can think of). It's silly to code things in oddball ways just to avoid a call you don't like the looks of.

Related

Guava's Streams::findLast implementation

I am looking into the implementation of Streams::findLast from Guava and while trying to understand it, there were a couple of things that simply I could not grasp. Here is it's implementation:
public static <T> java.util.Optional<T> findLast(Stream<T> stream) {
class OptionalState {
boolean set = false;
T value = null;
void set(#Nullable T value) {
set = true;
this.value = value;
}
T get() {
checkState(set);
return value;
}
}
OptionalState state = new OptionalState();
Deque<Spliterator<T>> splits = new ArrayDeque<>();
splits.addLast(stream.spliterator());
while (!splits.isEmpty()) {
Spliterator<T> spliterator = splits.removeLast();
if (spliterator.getExactSizeIfKnown() == 0) {
continue; // drop this split
}
// Many spliterators will have trySplits that are SUBSIZED even if they are not themselves
// SUBSIZED.
if (spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
// we can drill down to exactly the smallest nonempty spliterator
while (true) {
Spliterator<T> prefix = spliterator.trySplit();
if (prefix == null || prefix.getExactSizeIfKnown() == 0) {
break;
} else if (spliterator.getExactSizeIfKnown() == 0) {
spliterator = prefix;
break;
}
}
// spliterator is known to be nonempty now
spliterator.forEachRemaining(state::set);
return java.util.Optional.of(state.get());
}
Spliterator<T> prefix = spliterator.trySplit();
if (prefix == null || prefix.getExactSizeIfKnown() == 0) {
// we can't split this any further
spliterator.forEachRemaining(state::set);
if (state.set) {
return java.util.Optional.of(state.get());
}
// fall back to the last split
continue;
}
splits.addLast(prefix);
splits.addLast(spliterator);
}
return java.util.Optional.empty();
}
In essence the implementation is not that complicated to be honest, but here are the things that I find a bit weird (and I'll take the blame here if this question gets closed as "opinion-based", I understand it might happen).
First of all is the creation of OptionalState class, this could have been replaced with an array of a single element:
T[] state = (T[]) new Object[1];
and used as simple as:
spliterator.forEachRemaining(x -> state[0] = x);
Then the entire method could be split into 3 pieces:
when a certain Spliterator is known to be empty:
if (spliterator.getExactSizeIfKnown() == 0)
In this case it's easy - just drop it.
then if the Spliterator is known to be SUBSIZED. This is the "happy-path" scenario; as in this case we can split this until we get to the last element. Basically the implementation says: split until the prefix is either null or it's empty (in which case consume the "right" spliterator) or if after a split the "right" spliterator is known to be empty, consume the prefix one. This is done via:
// spliterator is known to be nonempty now
spliterator.forEachRemaining(state::set);
return java.util.Optional.of(state.get());
Second question I have is actually about this comment:
// Many spliterators will have trySplits that are SUBSIZED
// even if they are not themselves SUBSIZED.
This is very interesting, but I could not find such an example, would appreciate if someone would introduce me to one. As a matter of fact, because this comment exists, the code in the next (3-rd part of the method can not be done with a while(true) like the second), because it assumes that after a trySplit we could obtain a Spliterator that is SUBSIZED, even if our initial one was not, so it has to go to the very beginning of findLast.
this part of the method is when a Spliterator is known not to be SUBSIZED and in this case it does not have a known size; thus it relies on how the Spliterator from the source is implemented and in this case actually a findLast makes little sense... for example a Spliterator from a HashSet will return whatever the last entry is in the last bucket...
When you iterate a Spliterator of an unknown size, you have to track whether an element has been encountered. This can be done by calling tryAdvance and using the return value or by using forEachRemaining with a Consumer which records whether an element has been encountered. When you go the latter route, a dedicated class is simpler than an array. And once you have a dedicated class, why not use it for the SIZED spliterator as well.
What’s strange to me, is that this local class, which only exists to be used as a Consumer, doesn’t implement Consumer but requires the binding via state::set.
Consider
Stream.concat(
Stream.of("foo").filter(s -> !s.isEmpty()),
Stream.of("bar", "baz"))
The Spliterator representing the entire stream can’t have the SIZED characteristic. But when splitting off the first substream with the unknown size, the remaining stream has a known size.
Test code:
Spliterator<String> sp = Stream.concat(
Stream.of("foo").filter(s -> !s.isEmpty()),
Stream.of("bar", "baz"))
.spliterator();
do {
System.out.println(
"SIZED: "+sp.hasCharacteristics(Spliterator.SIZED)
+ ", SUBSIZED: "+sp.hasCharacteristics(Spliterator.SUBSIZED)
+ ", exact size if known: "+sp.getExactSizeIfKnown());
} while(sp.trySplit() != null);
Result:
SIZED: false, SUBSIZED: false, exact size if known: -1
SIZED: true, SUBSIZED: true, exact size if known: 2
SIZED: true, SUBSIZED: true, exact size if known: 1
But to me, it looks weird when someone tells in a comment to know that splitting can change the characteristics and then doing a pre-test with SUBSIZED, instead of just doing the split and check whether the result has a known size. After all, the code is doing the split anyway, in the alternative branch, when the characteristic is not present. In my old answer, I did the pretest to avoid allocating data structures, but here, the ArrayDeque is always created and used. But I think, even my old answer could be simplified.
I’m not sure what you are aiming at. When a Spliterator has the ORDERED characteristic, the order of traversal and splitting is well-defined. Since HashSet is not ordered, the term “last” is meaningless. If you are radical, you could optimize the operation to just return the first element for unordered streams; that’s valid and much faster.
What is strange, is this condition:
if (prefix == null || prefix.getExactSizeIfKnown() == 0) {
// we can't split this any further
(and a similar loop termination in the SUBSIZED path)
Just because one prefix happened to have a known zero size, it does not imply that the suffix can’t split further. Nothing in the specification says that.
As a consequence of this condition, Stream.concat(Stream.of("foo"), Stream.of("bar","baz")) can be handled optimally, whereas for Stream.concat(Stream.of(), Stream.of("bar", "baz")), it will fall back to a traversal, because the first prefix has a known size of zero.

How to cleanly process java 8 stream "findFirst()" result even if empty

One area that I often finding confusing with java 8 streams is when an intermediate result can be empty, and you need to take alternate paths if it's empty or not empty.
For instance, if I have code like this:
String pymtRef = defaultValue;
Optional<PaymentTender> paymentTender = paymentTenders.stream()
.filter(pt -> (pt.getFlag() == Flag.N || pt.getFlag() == null)).findFirst();
if (paymentTender.isPresent()) {
pymtRef = paymentTender.get().getId();
}
return pymtRef;
I would like to figure out how to remove the conditional block and do this in a single stream.
If I simply call ".map" on the filter result, that can work if it found a matching entry. If not, I get a NoSuchElementException.
I might instead use "ifPresent()", but the return type of that is "void".
Is there any way to make this cleaner?
Update:
The solution using "orElse()" works fine.
The entire method now looks something like this:
public String getPaymentReference(OrderContext orderContext) {
List<PaymentTender> paymentTenders = getPaymentTenders(orderContext);
if (paymentTenders.size() == 1) {
return paymentTenders.get(0).getId();
}
return paymentTenders.stream()
.filter(pt -> (pt.getAutoBill() == AutoBill.N || pt.getAutoBill() == null))
.findFirst().map(pt -> pt.getId()).orElse(DEFAULT_VALUE);
}
Can you think of a way to include the first conditional in the stream without making it more complex?
Calling get() straight after map will yield an exception if the Optional has an empty state, instead call orElse after map and provide a default value:
paymentTenders.stream()
.filter(pt -> (pt.getFlag() == Flag.N || pt.getFlag() == null))
.findFirst()
.map(PaymentTender::getId)
.orElse(someDefaultValue);
Edit:
As for:
Can you think of a way to include the first conditional in the stream
without making it more complex?
No, this is better the way you've done it. it's more readable and easier to follow.
introducing any type of logic to make it into one pipeline (if possible) will just end of being complex and hence harder to follow and understand.
You can do it in one statement via
public String getPaymentReference(OrderContext orderContext) {
List<PaymentTender> paymentTenders = getPaymentTenders(orderContext);
return paymentTenders.stream()
.filter(paymentTenders.size() == 1? pt -> true:
pt -> pt.getAutoBill() == AutoBill.N || pt.getAutoBill() == null)
.findFirst().map(PaymentTender::getId).orElse(DEFAULT_VALUE);
}
Note that this will not repeat the evaluation of the paymentTenders.size() == 1 for every element, but use a different function, depending on the state. When the condition is fulfilled, pt -> true will accept any element, which will result in the sole element being accepted as intended. Otherwise, the ordinary predicate, pt -> pt.getAutoBill() == AutoBill.N || pt.getAutoBill() == null is used.

Getting java.lang.illegalArgumentException : comparison method violates its general contract ! while using Comparator to sort a list [duplicate]

This question already has answers here:
Comparison Method violates its general contract in Java 7
(3 answers)
Closed 4 years ago.
I am trying to sort a list in a specific way in Java, and I found that Comparator is a good way to do so.
I will share with you a pseudo code of the problem.
I have a list of DTOs and let's say I want to sort it by a property(String) in a specific order, for example properties starting with "Hi" should be on top and the rest should be below.
Here is my pseudo code :
list.sort(new Comparator<myDto>(){
#Override
public int compare(myDto o1, myDto o2){
if(o1.getProperty1() != null && o2.getProperty1() == null)
return -1;
else if(o1.getProperty1() == null && o2.getProperty1() != null)
return 1;
else if(o1.getProperty1().startsWith("Hi") && o2.getProperty1().startsWith("Hi"))
return 0;
else if(o1.getProperty1().startsWith("Hi") && !o2.getProperty1().startsWith("Hi"))
return -1;
return 1;
}
});
I used like 4, 5 DTO's I created myself to test, but when I inject a file of 14k DTO's I get a java.lang.illegalArgumentException.
Any ideas ?
Change your final return 1 to return o1.getProperty1().compareTo(o2.getProperty1()) the JVM can compare elements a, b or b, a - if you just return 1 at the end then you will always violate the general contract.
In the other answers, you can find explanation why your Comparator doesn't work - in short, your returning 1 at the end makes the Comparator inconsistent (compare(a,b) != -compare(b,a)).
Direct Comparator implementations are hard to both write and read. That's why in Java 8, you can use the functional approach using various Comparator methods.
Translating your Comparator to the functional approach yields:
Comparator<String> property1Comparator = Comparator.nullsLast(Comparator.comparing(
property1 -> !property1.startsWith("Hi")
));
Comparator<MyDto> myDtoComparator = Comparator.comparing(MyDto::getProperty1, property1Comparator);
I believe this approach is much more readable than all the direct Comparator implementations.
PS. If you wanted to achieve the same result as in Elliot's solution (which additionally sorts the strings not prefixed with "Hi" in a natural order), you'd need the following property1Comparator:
Comparator<String> property1Comparator = Comparator.nullsLast(Comparator.<String, Boolean>comparing(
property1 -> !property1.startsWith("Hi")
).thenComparing(Comparator.naturalOrder()));
In your text, you say you want those objects starting with "Hi" before (less than) the other ones. In addition, your code implies that you want nulls at the end (higher than anything else). So your Comparator has to consider 9 cases (Hi, non-Hi, null for o1 in combination with Hi, non-Hi, null for o2) and return the following values:
o1=Hi: 0,-1,-1 for o2=Hi,non-Hi,null
o1=non-Hi: 1, 0,-1 for o2=Hi,non-Hi,null
o1=null: 1, 1, 0 for o2=Hi,non-Hi,null
Your code doesn't follow that table, e.g. for a non-Hi/non-Hi you'll always return 1 instead of 0, e.g. when doing compare("Peter","John") as well as compare("John","Peter"). As Elliot already pointed out, it's crucial that compare(a,b) and compare(b,a) either both return 0 or return results with opposite signs.
P.S. The table assumes you don't care for the ordering within the three groups. If you want one, you can replace the zeroes with the result of e.g. a lexical comparator.
You have to consider that a.compareTo(b) == -b.compareTo(a). Your last test just assumed that if either start with "Hi" you can return 1 but this breaks the rule above. What you can do is something like this.
list.sort((o1, o2) -> {
String o1p1 = o1.getProperty1(), o2p1 = o2.getProperty1();
boolean isNull1 = o1p1 == null, isNull2 = o2p1 == null;
if (isNull1)
return isNull2 ? 0 : -1;
else if (isNull2)
return +1;
boolean o1p1hi = o1p1.startsWith("Hi"), o2p1hi = o1p1.startsWith("Hi");
if (o1p1hi)
return o2p1hi ? 0 : -1;
else if (o2p1hi)
return +1;
return o1p1.compareTo(o2p1);
});

How to check if Set B has at least one element that is not in Set A

So I have two sets: A and B. I need to check if set B contains anything that is not in the set A. There are maybe intersections, so I cannot just check if set A contains set B.
I can obviously do this:
for (String string : setA) {
if (!setB.contains(string) {
break;
}
}
or using the Guava library:
Sets.intersection(setA, setB).containsAll(setB); // returns false if there are elements outside.
But is there any way that would perform better or may be just cleaner or more elegant?
Thanks.
“B contains an element not in A” is the exact opposite of “A contains all elements of B”, therefore, the already existing method containsAll is sufficient to answer that question.
if(!setA.containsAll(setB)) {
System.out.println("setB contains an element not in setA");
}
You may shortcut using setB.size()>setA.size() || !setA.containsAll(setB), but this requires that the sets agree on the definition of equality, e.g. if one set is a SortedSet using String.CASE_INSENSITIVE_ORDER as comparator and the other is a HashSet, this won’t work (but the definition of the correct outcome is tricky with such combinations anyway).
If setB is really large, you might get a benefit from using a parallel stream like
if(!setB.parallelStream().allMatch(setA::contains)) {
System.out.println("setB contains an element not in setA");
}
but this is rather rare.
Merge all elements into another set and compare the total elements:
Set ab = new Set(a);
ab.addAll(b);
if (ab.size() != b.size()) break; // that means `a` had some element that was not in b
Another way to use streams (parallel) and functional mix
setB.parallelStream().filter(((Predicate<String>)setA::contains).negate()).findFirst();
same as
setB.parallelStream().filter(bi -> { return !setA.contains(bi);}).findFirst();
Straight Java
Duplicate the "target" set.
duplicateSet.removeAll(otherSet)
If duplicateSet is not empty, then the target contains one or more elements that are not in the "otherSet"
Apache SetUtils
xyz = SetUtils.difference(seta, setb);
if xyz.size() > 0 then seta contains one or more elements that are not in setb.
You can try algorithm with removing elements from setB:
if (setB.size() > setA.size()) {
return true;
}
for (String s : setA) {
//boolean contains = setB.contains(s);
boolean contains = setB.remove(s);
if (contains) return true;
}

Checking that at least Value in HashMap matches?

I am trying to figure out how to iterate through my HashMap to see if at least one Value in it matches what I am looking for.
for(int i=0; i<allDogsInkennels.size(); i++){
Map<String, DogStatus> allDogsStatus = allDogsInKennels.get(i).getAllStatuses();
}
How can I add an If statement / loop here to check that at least one of the statuses matches e.g. "APPROVED".
Note: String= the Dogs Id
,DogStatus= Enum showing dog's status
if (allDogsStatus.containsValue(DogStatus.APPROVED)) {
// ...
}
You can iterate over the map and stop if you hit a match:
boolean found = false;
for (DogStatus value : allDogsStatus.values()) {
if (value == DogStatus.APPROVED) {
found = true;
break;
}
}
Even better is to refactor the above into a function that return the boolean.
Edit: I feel dumb for not remembering the containsValue method. That's probably the best approach, even though complexity is the same.

Categories

Resources