I am trying to understand the difference between passing a Closure vs a Comparator to the min function on a collection:
// Example 1: Closure/field/attribute?
Sample min = container.min { it.timespan.start }
// Example 2: Comparator
Sample min2 = container.min(new Comparator<Sample>() {
#Override
int compare(Sample o1, Sample o2) {
return o1.timespan.start <=> o2.timespan.start
}
})
They both return the correct result.
Where:
class Sample {
TimeSpan timespan
static constraints = {
}
}
And:
class TimeSpan {
LocalDate start
LocalDate end
}
In Example 1 I just pass the field timespan.start to min which I guess means that I am passing a Closure (even though its just a field in a class)?
In Example 1 does groovy convert the field timespan.start into a Comparator behind the scenes like the one I create explicitly in Example 2?
The difference is, that those are two different min methods both
taking different arguments. There is one for passing
a closure
and one for the
comparator
(there is a third one using identity and some deprecated ones, but we can ignore that for now).
The first version (Closure with one (implicit argument)) you have to
extract the value from the passed value, you want to make the min
aggregate with. Therefor this versions has some inner working to deal
with comparing the values.
But the docs also state:
If the closure has two parameters it is used like a traditional
Comparator. I.e. it should compare its two parameters for order,
returning a negative integer, zero, or a positive integer when the
first parameter is less than, equal to, or greater than the second
respectively. Otherwise, the Closure is assumed to take a single
parameter and return a Comparable (typically an Integer) which is then
used for further comparison.
So you can use a Closure version also to the same as your second example
(you have to define two params explicitly):
container.min{ a, b -> a <=> b }
And there is also a shorter version of the second example. You can cast
a Closure to an interface with groovy. So this works too:
container.min({ a, b -> a <=> b } as Comparator)
Related
In the documentation of compareTo function, I read:
Returns zero if this object is equal to the specified other object, a
negative number if it's less than other, or a positive number if it's
greater than other.
What does this less than or greater than mean in the context of strings? Is -for example- Hello World less than a single character a?
val epicString = "Hello World"
println(epicString.compareTo("a")) //-25
Why -25 and not -10 or -1 (for example)?
Other examples:
val epicString = "Hello World"
println(epicString.compareTo("HelloWorld")) //-55
Is Hello World less than HelloWorld? Why?
Why it returns -55 and not -1, -2, -3, etc?
val epicString = "Hello World"
println(epicString.compareTo("Hello World")) //55
Is Hello World greater than Hello World? Why?
Why it returns 55 and not 1, 2, 3, etc?
I believe you're asking about the implementation of compareTo method for java.lang.String. Here is a source code for java 11:
public int compareTo(String anotherString) {
byte v1[] = value;
byte v2[] = anotherString.value;
if (coder() == anotherString.coder()) {
return isLatin1() ? StringLatin1.compareTo(v1, v2)
: StringUTF16.compareTo(v1, v2);
}
return isLatin1() ? StringLatin1.compareToUTF16(v1, v2)
: StringUTF16.compareToLatin1(v1, v2);
}
So we have a delegation to either StringLatin1 or StringUTF16 here, so we should look further:
Fortunately StringLatin1 and StringUTF16 have similar implementation when it comes to compare functionality:
Here is an implementation for StringLatin1 for example:
public static int compareTo(byte[] value, byte[] other) {
int len1 = value.length;
int len2 = other.length;
return compareTo(value, other, len1, len2);
}
public static int compareTo(byte[] value, byte[] other, int len1, int len2) {
int lim = Math.min(len1, len2);
for (int k = 0; k < lim; k++) {
if (value[k] != other[k]) {
return getChar(value, k) - getChar(other, k);
}
}
return len1 - len2;
}
As you see, it iterated over the characters of the shorter string and in case the charaters in the same index of two strings are different it returns the difference between them. If during the iterations it doesn't find any different (one string is prefix of another) it resorts to the comparison between the length of two strings.
In your case, there is a difference in the first iteration already...
So its the same as `"H".compareTo("a") --> -25".
The code of "H" is 72
The code of "a" is 97
So, 72 - 97 = -25
Short answer: The exact value doesn't have any meaning; only its sign does.
As the specification for compareTo() says, it returns a -ve number if the receiver is smaller than the other object, a +ve number if the receiver is larger, or 0 if the two are considered equal (for the purposes of this ordering).
The specification doesn't distinguish between different -ve numbers, nor between different +ve numbers — and so neither should you. Some classes always return -1, 0, and 1, while others return different numbers, but that's just an implementation detail — and implementations vary.
Let's look at a very simple hypothetical example:
class Length(val metres: Int) : Comparable<Length> {
override fun compareTo(other: Length)
= metres - other.metres
}
This class has a single numerical property, so we can use that property to compare them. One common way to do the comparison is simply to subtract the two lengths: that gives a number which is positive if the receiver is larger, negative if it's smaller, and zero of they're the same length — which is just what we need.
In this case, the value of compareTo() would happen to be the signed difference between the two lengths.
However, that method has a subtle bug: the subtraction could overflow, and give the wrong results if the difference is bigger than Int.MAX_VALUE. (Obviously, to hit that you'd need to be working with astronomical distances, both positive and negative — but that's not implausible. Rocket scientists write programs too!)
To fix it, you might change it to something like:
class Length(val metres: Int) : Comparable<Length> {
override fun compareTo(other: Length) = when {
metres > other.metres -> 1
metres < other.metres -> -1
else -> 0
}
}
That fixes the bug; it works for all possible lengths.
But notice that the actual return value has changed in most cases: now it only ever returns -1, 0, or 1, and no longer gives an indication of the actual difference in lengths.
If this was your class, then it would be safe to make this change because it still matches the specification. Anyone who just looked at the sign of the result would see no change (apart from the bug fix). Anyone using the exact value would find that their programs were now broken — but that's their own fault, because they shouldn't have been relying on that, because it was undocumented behaviour.
Exactly the same applies to the String class and its implementation. While it might be interesting to poke around inside it and look at how it's written, the code you write should never rely on that sort of detail. (It could change in a future version. Or someone could apply your code to another object which didn't behave the same way. Or you might want to expand your project to be cross-platform, and discover the hard way that the JavaScript implementation didn't behave exactly the same as the Java one.)
In the long run, life is much simpler if you don't assume anything more than the specification promises!
I am new to Groovy so I am a bit confused by the run time binding, typed and not typed attributes of the language. Personally I prefer types to be declared.
However, I have a question.
I have a small method that takes some variable from maps, input, whatever, that I know are numbers. Let's say that I don't know what the initial type was (it's somewhere deep in the code or comes from an external source), other that it was a number. Now I have a method that takes two of these arguments and I have to do a modulo operation on them. Because they might be decimal or not, I wrote a small method using the remainder of BigDecimal so to enforce the type I used the type BigDecimal on the method signature.
def callerMethod(Map map) {
...
map.each{
calledMethod(it.val1, it.val2)
...
}
...
}
def calledMethod(BigDecimal val1, BigDecimal val2) {
...
vl1.remainder(val2)
...
}
Is this correct? If the incoming argument is Integer (most of the time the primitives are boxed if I understand it correctly), will it be implicitly cast or turned into a BigDecimal?
How does this work in Groovy.
I still think that since I have the option to use types, I want to use them rather than declaring everything def. It also makes it easier to read code or see what something is if you reading already existing code
The problem in this methods are not the type of variables, is the each of your map
In a groovy Map, the each have two signatures.
One receive a Map.Entry of parameter and other receive key and value
Ex.:
Map map = [key1:'value1',key2:'value2']
map.each{ Map.Entry entryMap ->
println "The value of key: ${entryMap.key} is ${entryMap.value}"
}
The result of this each will be:
The value of key: key1 is value1
The value of key: key2 is value2
Or could be like this
Map map = [key1:'value1',key2:'value2']
map.each{ def key, def value ->
println "The value of key: ${key} is ${value}"
}
And the result of this second will be the same of the first.
If you want to pass two specific arguments to you calledMethod, pass both outside of the each like this:
def callerMethod(Map map) {
calledMethod(map.val1, map.val2)
}
I don't understand perfectly what you want.. I hope that's help you to do you code.
class ArgumentClass{
int var;
}
class ClassMocked{
int aMothod(ArgumentClass argumentClass){
return anInt;
}
}
class MyTest{
Mock and Stub here
}
In MyTest, I want to stub aMothod such that it returns the value basing on value of ArgumentClass.var. And I have to do it in one go.
In other words, I have a test case where a moehod is called three times by the app code and basing on a variable in an argument object, I need different return values. I need to stub accordingly. Please let me know if there is a way.
If I understand that correctly you can do it in two different way with mockito. If you declare ClassMocked as a mock you should be able to say this:
when(mock.aMothod(eq(specificArgument))).thenReturn(1);
when(mock.aMothod(eq(anotherSpecificArgument))).thenReturn(2);
If you want to do it that regardless of the argument passed you want to return values based on the number of invocation of the method you can say:
when(mock.aMothod(any())).thenReturn(1, 2);
This says that when aMothod is called regardless of the parameter passed (any()) it will return in the first call 1 and when called second time it will return 2.
Though you can have your mock return values in the right order, as in karruma's answer, you may also use an Answer to calculate the mocked value:
when(mock.aMothod(any())).thenAnswer(new Answer<Integer>() {
#Override public Integer answer(InvocationOnMock invocation) {
ArgumentClass argument = invocation.getArguments()[0];
return calculationBasedOn(argument);
}
});
Or in Java 8 and Mockito 2 beta (untested, may need boxing/unboxing casts):
when(mock.aMothod(any())).thenAnswer(invocation ->
calculatebasedOn(invocation.getArgumentAt(0, ArgumentClass.class)));
Though I have an anonymous inner class in the top sample, naturally, you can make a named Answer subclass and reuse it across your application.
I have a question about using the new Objects.compare(o1, o2, Comparator) method - from my own testing of it, if both o1 and o2 are null then it returns 0, however, if one of them is null then it still throws a null pointer exception. I have found a lot of material on Objects.equals and some of the other Objects utility methods but not much at all on Objects.compare and when we are expected to use it / replace old code with it.
So here I could do this:
String s1 = "hi";
String s2 = "hi";
int x = Objects.compare(s1, s2, Comparator.naturalOrder());
System.out.println("x = " + x);
That works fine, returns 0, now this:
String s1 = null;
String s2 = null;
Also works fine and returns 0. However, this:
String s1 = "hi";
Strng s2 = null;
Throws a NullPointerException. I'm guessing the benefit of Objects.compare(o1,o2,Comparator) vs o1.compareTo(o2) is that it at least handles circumstances where both objects are null and when one of them is null it allows you to design a Comparator to handle it. I'm supposing, e.g.
int x = Objects.compare(s1, s2, Comparator.nullsFirst(Comparator.naturalOrder()));
Whereas with x.compareTo(y) there's no way to handle null unless you do so beforehand? So do the Java library developers now intend us to replace all calls to compareTo with Objects.compare, when we're concerned about nulls? e.g. would we do this in our Comparable implementations?
Side query 1: With regards to using nullsFirst if you use it then pass in a Comparator, which is chained using comparing, thenComparing, etc, does it apply to all of the inner comparators? e.g.
Comparator.nullsFirst(Comparator.comparing(Song::getTitle)
.thenComparing(Song::getArtist)
.thenComparing(Song::getDuration)
)
Would that apply nullsFirst to everything inside or do you need to use nullsFirst individually on each of them? I think from testing that it only applies to the actual Song objects being null, not for the fields of title or artist being null, i.e. if they are null then a NullPointerException is still thrown. Anyway around that?
Side query 2: final question is that because I like the Comparator.comparing syntax, I'm proposing to start to write my compareTo implementions using it - I was struggling to think how to replace this traditional approach, e.g.
public int compareTo(Song other) {
int result = this.title.compareTo(other.title);
if (result == 0) {
result = this.artist.compareTo(other.artist);
if (result == 0) {
result = Integer.compare(this.duration, other.duration);
}
}
return result;
}
then I thought I could use Objects.compare(...) as follows:
public int compareTo(Song other) {
return Objects.compare(this, other, Comparator.nullsFirst(
Comparator.comparing(Song::getTitle)
.thenComparing(Song::getArtist)
.thenComparingInt(Song::getDuration)
));
}
I thought this version was more elegant - I am assuming it is working as I think it is, e.g. by passing this and other as the first 2 arguments then the comparator, it has the same effect as the traditional compareTo approach with if statements? Whilst I can see that the benefit of Objects.compare catching two nulls would never occur as if this was null then the compareTo method call would never be reached (either by handling the exception or it being thrown). But by using nullsFirst I suppose if the argument passed in, i.e. other, was null, then this would handle this safely?
Many thanks in advance for any help.
Objects.compare is not meant to provide a null safe comparison, since there is no default behavior that could be implemented. It just implements a shortcut of not invoking the Comparator’s method when both objects are identical. In other words, it does a==b? 0: c.compare(a, b), nothing more. So not breaking when both objects are null is just a side-effect. The encapsulated code might look trivial but the other methods in this class are of a similar category. Using small utility methods a lot might still result in a notable win.
By the way, it’s not a Java 8 method at all. It exists since Java 7.
Regarding your second question, Comparator.nullsFirst(…) decorates an existing Comparator and will enforce the rule for null values before delegating to the provided comparator as it is the purpose of this comparator to shield the existing one from ever seeing null values. It doesn’t matter whether the decorated comparator is a chained one or not. As long as it is what you called the “inner comparator”, as
you must not invoke thenComparing on the result of nullsFirst as that would imply calling the next comparator when both values are null.
Comparator.nullsFirst(Comparator.comparing(a).thenComparing(b)) // perfect
Comparator.nullsFirst(Comparator.comparing(a)).thenComparing(b) // ouch
Now to your third question, implementing a compareTo method using a nullsFirst comparator is violating the interface specification:
The implementor must ensure sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y. (This implies that x.compareTo(y) must throw an exception iff y.compareTo(x) throws an exception.)
This implies that passing null as argument should always result in a NullPointerException as swapping argument and receiver would throw as well, unconditionally.
Orders including a null policy should always be provided as separate Comparators.
Note that it would also be quite inefficient as you would create a new Comparator (multiple Comparators, to be precise) for every compareTo call. Now image sorting a rather large list of these objects…
What I normally do for your final question is to first create a static comparator reference within the class:
public static final Comparator<Song> COMP_DEFAULT
= nullsFirst(comparing(Song::getTitle, nullsFirst(naturalOrder()))
.thenComparing(Song::getArtist, nullsFirst(naturalOrder()))
.thenComparingInt(Song::getDuration));
And then refer to this comparator in compareTo
public int compareTo(Song other) {
return COMP_DEFAULT.compare(this, other);
}
This way you're not recreating your comparator for each compareTo call, null safety of Song is guaranteed as is the result of a.comparetTo(b) == b.compareTo(a).
We also ensure null safety of each property by using nullsFirst(naturalOrder()) for the passed in key comparator (second argument).
As the Comparator returned is immutable it can be made public which can be handy for bundling some alternate Comparators with the class that consumers may use.
I see in the API docs there is a sort() method on List, but I'm not clear what it needs for a parameter. The current need is for a very simple straight up alpha comparison.
1. A Quick Solution
Thanks for the question! You can sort a list of Strings like this:
main() {
final List<String> fruits = <String>['bananas', 'apples', 'oranges'];
fruits.sort();
print(fruits);
}
The above code prints:
[apples, bananas, oranges]
2. Slightly more advanced usage
Notice that sort() does not return a value. It sorts the list without creating a new list. If you want to sort and print in the same line, you can use method cascades:
print(fruits..sort());
For more control, you can define your own comparison logic. Here is an example of sorting the fruits based on price.
main() {
final List<String> fruits = <String>['bananas', 'apples', 'oranges'];
fruits.sort((a, b) => getPrice(a).compareTo(getPrice(b)));
print(fruits);
}
Let's see what's going on here.
A List has a sort method, which has one optional parameter: a Comparator. A Comparator is a typedef or function alias. In this case, it's an alias for a function that looks like:
int Comparator(T a, T b)
From the docs:
A Comparator function represents such a total ordering by returning a negative integer if a is smaller than b, zero if a is equal to b, and a positive integer if a is greater than b.
3. How to do it with a list of custom objects
Additionally, if you create a list composed of custom objects, you could add the Comparable<T> as a mixin or as inheritance (extends) and then override the compareTo method, in order to recreate the standard behavior of sort() for your list of custom objects. For more info, do check out this other, related StackOverflow answer.
Here is the one line code to achieve it.
fruits.sort((String a, String b)=>a.compareTo(b)); //fruits is of type List<String>
For Sorting Simple List of Integers or Strings:
var list = [5 , -5 ,1];
list.sort(); //-5 , 1 , 5
For Reversing the list order:
list.reversed;
For Sorting List of Objects or Map by field of it:
List<Map<String, dynamic>> list= [
{"name": "Shoes", "price": 100},
{"name": "Pants", "price": 50},
];
// from low to high according to price
list.sort((a, b) => a["price"].compareTo(b["price"]));
// from high to low according to price
list.sort((a, b) => b["price"].compareTo(a["price"]));
To add just one point to Seth's detailed answer, in general, in
(a, b) => foo(a, b)
passed into sort, the function foo should answer an integer result as follows:
if a < b, result should be < 0,
if a = b, result should be = 0, and
if a > b, result should be > 0.
For the above law of trichotomy to hold, both a and b must be Comparables.
use compareAsciiUpperCase instead of compareTo, as it supports strings and automatically ignores case sensitive:
import "package:collection/collection.dart";
data.sort((a, b) {
return compareAsciiUpperCase(a.name, b.name);
});
After today, you should just be able to do list.sort() .
The sort method's argument is now optional, and it defaults to a function that calls compareTo on the elements themselves. Since String is Comparable, it should Just Work now.
How I have solved this problem.
List<Product> _dataSavingListProducts = [];
List<Product> _dataSavingListFavoritesProducts = [];
void _orderDataSavingLists() {
_dataSavingListProducts.toList().reversed;
_dataSavingListFavoritesProducts.toList().reversed;
}