How does Java know which String::compareTo method reference to use when calling Collections.sort(someListOfStrings, String::compareTo);? compareTo is not static and it needs to know the value of the "left hand side" of the comparison.
Suppose that you use method reference for Comparator interface:
Comparator<String> cmp = String::compareTo;
When you call the cmp.compare(left, right) (which is "single abstract method" or "SAM" of Comparator interface), the magic occurs:
int result = cmp.compare(left, right);
| |
/------------------------/ |
| /---------------/
| |
left.compareTo(right);
Basically all the parameters of SAM are converted to the parameters of the referred method, but this object (which is on the left side) is also counted as parameter.
OK, the source of Collections.sort() looks as follows:
public static <T> void sort(List<T> list, Comparator<? super T> c) {
Object[] a = list.toArray();
Arrays.sort(a, (Comparator)c);
ListIterator i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set(a[j]);
}
}
I think it is quite clear now. The contents is a list. It means it has an order and the items are treated one by one in that order.
Related
I want to be able to do something like this:
for(i = 0; i < 10; i++) {
//if any button in the array is pressed, disable it.
button[i].setOnAction( ae -> { button[i].setDisable(true) } );
}
However, I get a error saying "local variables referenced from a lambda expression must be final or effectively final". How might I still do something like the code above (if it is even possible)? If it can't be done, what should be done instead to get a similar result?
As the error message says, local variables referenced from a lambda expression must be final or effectively final ("effectively final" meaning the compiler can make it final for you).
Simple workaround:
for(i = 0; i < 10; i++) {
final int ii = i;
button[i].setOnAction( ae -> { button[ii].setDisable(true) } );
}
Since you are using lambdas, you can benefit also from other features of Java 8, like streams.
For instance, IntStream:
A sequence of primitive int-valued elements supporting sequential and parallel aggregate operations. This is the int primitive specialization of Stream.
can be used to replace the for loop:
IntStream.range(0,10).forEach(i->{...});
so now you have an index that can be used to your purpose:
IntStream.range(0,10)
.forEach(i->button[i].setOnAction(ea->button[i].setDisable(true)));
Also you can generate a stream from an array:
Stream.of(button).forEach(btn->{...});
In this case you won't have an index, so as #shmosel suggests, you can use the source of the event:
Stream.of(button)
.forEach(btn->btn.setOnAction(ea->((Button)ea.getSource()).setDisable(true)));
EDIT
As #James_D suggests, there's no need of downcasting here:
Stream.of(button)
.forEach(btn->btn.setOnAction(ea->btn.setDisable(true)));
In both cases, you can also benefit from parallel operations:
IntStream.range(0,10).parallel()
.forEach(i->button[i].setOnAction(ea->button[i].setDisable(true)));
Stream.of(button).parallel()
.forEach(btn->btn.setOnAction(ea->btn.setDisable(true)));
Use the Event to get the source Node.
for(int i = 0; i < button.length; i++)
{
button[i].setOnAction(event ->{
((Button)event.getSource()).setDisable(true);
});
}
Lambda expressions are effectively like an annonymous method which works on stream. In order to avoid any unsafe operations, Java has made that no external variables which can be modified, can be accessed in a lambda expression.
In order to work around it,
final int index=button[i];
And use index instead of i inside your lambda expression.
You say If the button is pressed, but in your example all the buttons in the list will be disabled. Try to associate a listener to each button rather than just disable it.
For the logic, do you mean something like that :
Arrays.asList(buttons).forEach(
button -> button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
button.setEnabled(false);
}
}));
I Also like Sedrick's answer but you have to add an action listener inside the loop .
There is no nice way to convert given boolean[] foo array into stream in Java-8 in one statement, or I am missing something?
(I will not ask why?, but it is really incomprehensible: why not add stream support for all primitive types?)
Hint: Arrays.stream(foo) will not work, there is no such method for boolean[] type.
Given boolean[] foo use
Stream<Boolean> stream = IntStream.range(0, foo.length)
.mapToObj(idx -> foo[idx]);
Note that every boolean value will be boxed, but it's usually not a big problem as boxing for boolean does not allocate additional memory (just uses one of predefined values - Boolean.TRUE or Boolean.FALSE).
You can use Guava's Booleans class:
Stream<Boolean> stream = Booleans.asList(foo).stream();
This is a pretty efficient way because Booleans.asList returns a wrapper for the array and does not make any copies.
of course you could create a stream directly
Stream.Builder<Boolean> builder = Stream.builder();
for (int i = 0; i < foo.length; i++)
builder.add(foo[i]);
Stream<Boolean> stream = builder.build();
…or by wrapping an AbstractList around foo
Stream<Boolean> stream = new AbstractList<Boolean>() {
public Boolean get(int index) {return (foo[index]);}
public int size() {return foo.length;}
}.stream();
Skimming through the early access JavaDoc (ie. java.base module) of the newest java-15, there is still no neat way to make the primitive boolean array work with Stream API together well. There is no new feature in the API with treating a primitive boolean array since java-8.
Note that there exist IntStream, DoubleStream and LongStream, but nothing like BooleanStream that would represent of a variation of a sequence of primitive booleans. Also the overloaded methods of Stream are Stream::mapToInt, Stream::mapToDouble and Stream::mapToLong, but not Stream::mapToBoolean returning such hypothetical BooleanStream.
Oracle seems to keep following this pattern, which could be found also in Collectors. There is also no such support for float primitives (there is for double primitives instead). In my opinion, unlike of float, the boolean support would make sense to implement.
Back to the code... if you have a boxed boolean array (ie. Boolean[] array), the things get easier:
Boolean[] array = ...
Stream<Boolean> streamOfBoxedBoolean1 = Arrays.stream(array);
Stream<Boolean> streamOfBoxedBoolean2 = Stream.of(array);
Otherwise you have to use more than one statement as said in this or this answer.
However, you asked (emphasizes mine):
way to convert given boolean[] foo array into stream in Java-8 in one statement.
... there is actually a way to achieve this through one statement using a Spliterator made from an Iterator. It is definetly not nice but :
boolean[] array = ...
Stream<Boolean> stream = StreamSupport.stream(
Spliterators.spliteratorUnknownSize(
new Iterator<>() {
int index = 0;
#Override public boolean hasNext() { return index < array.length; }
#Override public Boolean next() { return array[index++]; }
}, 0), false);
How does Java know which String::compareTo method reference to use when calling Collections.sort(someListOfStrings, String::compareTo);? compareTo is not static and it needs to know the value of the "left hand side" of the comparison.
Suppose that you use method reference for Comparator interface:
Comparator<String> cmp = String::compareTo;
When you call the cmp.compare(left, right) (which is "single abstract method" or "SAM" of Comparator interface), the magic occurs:
int result = cmp.compare(left, right);
| |
/------------------------/ |
| /---------------/
| |
left.compareTo(right);
Basically all the parameters of SAM are converted to the parameters of the referred method, but this object (which is on the left side) is also counted as parameter.
OK, the source of Collections.sort() looks as follows:
public static <T> void sort(List<T> list, Comparator<? super T> c) {
Object[] a = list.toArray();
Arrays.sort(a, (Comparator)c);
ListIterator i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set(a[j]);
}
}
I think it is quite clear now. The contents is a list. It means it has an order and the items are treated one by one in that order.
I've been using JoSQL for quite a few months now and today I came across a problem I am not sure how to solve. I probably could solve it by binding variables/placeholders, but I'd like to include the fields in the query.
SELECT * FROM ...MyObject WHERE getType != com.mypackage.myclass.TYPE_A
This is the query that I have. TYPE_A is a public static final int attribute in "myclass" class. Accessing methods (such as getType) is easy, because getType is expected to be a method from MyObject - just that I do not write round brackets after it (this is how JoSQL works as far as I know).
Does anyone happen to have an idea how to access a public static final field?
JoSQL uses gentlyweb-utils; it seems to be some sort of Accessor/Getter/Setter framework. I'd love to access that attribute without having to bind variables, but I haven't been able to do so.
Thanks for your help in advance! I really appreciate it.
I think I have figured something out. First: it seems not possible to access the static variables for whatever reason. I've used the following approach to solve my issue:
create a method, which picks up a given JoSQL-statement
mark the constants, which you want to replace, by say "{?FULL_PACKAGE_AND$CONSTANT}"
use reflections to determine the column as well as the column (and value) from the field
iteratively replace the statement until no "{?"-values are available
Example:
JoSQL-statement looks like this:
(isWeapon = TRUE AND getItem.getType2 = {?com.l2jserver.gameserver.model.items.L2Item$TYPE2_WEAPON})
Method using the query-object:
final Query query = DataLayer.createJoSqlQuery(joSql);
Method (pre)processing the JoSQL-statement:
final Query query = new Query();
int variableColumn = 0;
while (joSql.indexOf("{?") > -1) {
variableColumn++;
final int startIndex = joSql.indexOf("{?");
final int endIndex = joSql.indexOf("}", startIndex);
final String value = joSql.substring(startIndex + 2, endIndex);
try {
final Object variableValue = Class.forName(value.split("\\$")[0]).getField(value.split("\\$")[1]).get(null);
query.setVariable(variableColumn, variableValue);
joSql = joSql.replace("{?" + value + "}", "?");
}
catch (...) {
e.printStackTrace();
}
}
query.parse(joSql);
return query;
The JoSQL-statement preprocessing method bascially iterates through a given JoSQL-statement and sees whether it contains the string "{?". If it does, it does some copy and paste (note the dollar-symbol right in front of the constant name).
Finally it creates the objects and sets them using something similar to prepared statements "setObject"-method. In the end it just replaces the values within the JoSQL-statement with question marks ("?") and sets a corresponding object in the newly created Query-object, which is later used to retrieve information.
I'm a Java novice that is having some trouble overriding the compareTo method in the Comparable interface. My code creates a HashMap that associates strings to an int. I would like to override compareTo so that the strings in the ArrayList keys are sorted based on their HashMap values, not alphabetically. Under this implementation, however, the strings are still sorted alphabetically.
Oh, and to clarify, nameWeight is the HashMap of String,Integer pairs.
Any ideas?
List<String> keys = new ArrayList<String>(nameWeight.keySet());
System.out.println(keys);
Collections.sort(keys);
public int compareTo(String that){
int gtr = 1;
int less = -1;
int eql = 0;
System.out.print(this);
System.out.print(that);
if(that=="JOHN")
return less;
int valThis = nameWeight.get(this);
int valThat = nameWeight.get(that);
if(valThis==valThat)
return eql;
if(valThis>valThat)
return gtr;
if(valThis<valThat)
return less;
return gtr;
}
You're sorting a list of strings so the compareTo method called is the one defined in class String (or its superclass). Since you can't modify String you would have to create a subclass of String, override compareTo in that class and use List<StringSubClass>. But since String is final you're not allowed to subclass from it (thanks #pst).
Alternatively you don't use String objects in the list but objects of the type you created and in which you override compareTo (don't forget to add implements Comparable to the class definition).
Or (shameless plug from #pst again), and that is probably the best solution, you pass a comparator to the sort function which will be used to sort the strings instead of the default implementation.