JDK java.util.concurrent.ConcurrentSkipListSet.equals(Object o) implementation efficiency - performance

The equalsimplementatin of java.util.concurrent.ConcurrentSkipListSet in JDK is as following
public boolean equals(Object o) {
// Override AbstractSet version to avoid calling size()
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection<?> c = (Collection<?>) o;
try {
return containsAll(c) && c.containsAll(this);
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}
}
But I think the code below seems to be more efficient
public boolean myEquals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection<?> c = (Collection<?>) o;
if (c.size() != this.size()) {
return false;
}
Iterator ic = c.iterator();
Iterator id = iterator();
while (ic.hasNext() && id.hasNext()) {
if (!ic.next().equals(id.next())) {
return false;
}
}
return true;
}
And a simple test is also likely supporting the second equals
public class Test {
public static void main(String[] args) {
ConcurrentSkipListSet<Integer> set1 = new ConcurrentSkipListSet<Integer>();
ConcurrentSkipListSet<Integer> set2 = new ConcurrentSkipListSet<Integer>();
for (int i = 0; i < 10000000; i++) {
set1.add(i);
set2.add(i);
}
long ts = System.currentTimeMillis();
System.out.println(set1.equals(set2));
System.out.println(System.currentTimeMillis() - ts);
ts = System.currentTimeMillis();
System.out.println(myset1.myEquals(myset2));
System.out.println(System.currentTimeMillis() - ts);
}
}
Output result
true
2713
true
589
In the JDK comment it says, This definition ensures that the equals method works properly across different implementations of the set interface. Could anyone kindly explain this?

For reference, the OpenJDK thread resulted in creating JDK-8181146 ConcurrentSkipListSet.equals efficiency.
In the JDK comment it says, This definition ensures that the equals method works properly across different implementations of the set interface. Could anyone kindly explain this?
It comes from Set.equals(Object). Per the documentation:
Returns true if the specified object is also a set, the two sets have the same size, and every member of the specified set is contained in this set (or equivalently, every member of this set is contained in the specified set). This definition ensures that the equals method works properly across different implementations of the set interface.
It is implying that Set.equals implementations should be defined by the behavior of Set.contains(Object). Which then leads you to this verbiage from the java.util.SortedSet:
Note that the ordering maintained by a sorted set (whether or not an explicit comparator is provided) must be consistent with equals if the sorted set is to correctly implement the Set interface. (See the Comparable interface or Comparator interface for a precise definition of consistent with equals.) This is so because the Set interface is defined in terms of the equals operation, but a sorted set performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the sorted set, equal. The behavior of a sorted set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface.
So why the 'this contains that and that contains this' in the ConcurrentSkipListSet? First off you want to avoid the call to ConcurrentSkipListSet.size() because:
Beware that, unlike in most collections, this method is NOT a constant-time operation. Because of the asynchronous nature of these sets, determining the current number of elements requires traversing them all to count them. Additionally, it is possible for the size to change during execution of this method, in which case the returned result will be inaccurate. Thus, this method is typically not very useful in concurrent applications.
The second reason is that you want to be 'consistent with equals'.
Let's make a cruel example based off your code:
private static boolean myEquals(Set o1, Set o2) {
if (o1.size() == 1 && o2.size() == 1) {
Iterator ic = o2.iterator();
Iterator id = o1.iterator();
while (ic.hasNext() && id.hasNext()) {
if (!ic.next().equals(id.next())) {
return false;
}
}
return true;
}
return o1.equals(o2);
}
public static void main(String[] args) {
print(skiplist(new BigDecimal("1.0")), tree(new BigDecimal("1.00")));
print(skiplist(new BigDecimal("1.0")), hash(new BigDecimal("1.00")));
print(skiplist(new BigDecimal("1.0")), identity(new BigDecimal("1.00")));
print(skiplist(BigDecimal.ONE), identity(new BigDecimal(BigInteger.ONE, 0)));
}
private static Collection<BigDecimal> e() {
return Arrays.asList(new BigDecimal("1.0"));
}
private static <E> Set<E> hash(E... e) {
return new HashSet<>(Arrays.asList(e));
}
private static <E> Set<E> skiplist(E... e) {
return new ConcurrentSkipListSet<>(Arrays.asList(e));
}
private static <E> Set<E> tree(E... e) {
return new TreeSet<>(Arrays.asList(e));
}
private static <E> Set<E> identity(E... e) {
Set<E> s = Collections.newSetFromMap(new IdentityHashMap<E, Boolean>());
Collections.addAll(s, e);
return s;
}
private static void print(Set o1, Set o2) {
System.out.println(o1.getClass().getName()
+ "==" + o2.getClass().getName() + ": "
+ o1.equals(o2) + ": " + myEquals(o1, o2));
System.out.println(o2.getClass().getName()
+ "==" + o1.getClass().getName() + ": " + o2.equals(o1)
+ ": " + myEquals(o2, o1));
}
Which outputs:
java.util.concurrent.ConcurrentSkipListSet==java.util.TreeSet: true: false
java.util.TreeSet==java.util.concurrent.ConcurrentSkipListSet: true: false
java.util.concurrent.ConcurrentSkipListSet==java.util.HashSet: false: false
java.util.HashSet==java.util.concurrent.ConcurrentSkipListSet: false: false
java.util.concurrent.ConcurrentSkipListSet==java.util.Collections$SetFromMap: false: false
java.util.Collections$SetFromMap==java.util.concurrent.ConcurrentSkipListSet: false: false
java.util.concurrent.ConcurrentSkipListSet==java.util.Collections$SetFromMap: false: true
java.util.Collections$SetFromMap==java.util.concurrent.ConcurrentSkipListSet: false: true
That output shows that the new implementation would not be consistent with equals:
The natural ordering for a class C is said to be consistent with equals if and only if e1.compareTo(e2) == 0 has the same boolean value as e1.equals(e2) for every e1 and e2 of class C. Note that null is not an instance of any class, and e.compareTo(null) should throw a NullPointerException even though e.equals(null) returns false.
Now we could fix this by replacing the element check with
((Comparable) e1).compareTo((Comparable) e2) != 0 or Comparator.compare(e1, e2) != 0 and add checks to try to determine that the two sets use the same ordering but keep in mind that collections can be wrapped and there is nothing stopping a caller from hiding the fact that a set is backed by sorted set. Now you are back to the 'this contains that and that contains this' implementation of equals which can deal with collection wrappers.
Another nice property of the 'this contains that and that contains this' implementation is that the equals implementation is not creating an iterator object for the given collection which in the worst case could have an implementation like Arrays.asList(s.toArray()).iterator() under the hood.
Without relaxing spec, relaxing the existing behavior, or adding a collection method that returns a BiPredicate to capture the 'equivalence relationship' for a collection, I think it will be hard to add an optimization like this to the JDK.

Related

Xposed - Return class constructor

Decompilled method:
private static l c(String str, String str2, String str3, String str4) {
l lVar;
k kVar = (k) m.get(str);
j jVar = (j) l.get(str);
if (kVar != null) {
lVar = new l(kVar, str2, str3);
} else if (jVar != null) {
lVar = new l(jVar, str2, str3);
} else {
lVar = new l(j.GENERIC, str2, str3);
}
lVar.a(str4);
return lVar;
}
How to use Xposed to return new l (jVar, str2, str3) with its specific values?
The beginning of the code I have is:
try {
findAndHookMethod("com.xiaomi.hm.health.ui.smartplay.h", lpparam.classLoader, "c", String.class, String.class, String.class, String.class, new XC_MethodHook() {
#Override
protected void afterHookedMethod(MethodHookParam param) {
String pkg = (String) param.args[0];
if (pkg == "com.perm.kate_new_6"){
return ???;
}
}
});
} catch (Throwable t) {
t.printStackTrace();
}
The XC_MethodHook's afterHookedMethod method needs to return void. I.e., the return of the hooked method needs be be set via setResult method of XC_MethodHook instead.
Internally it sets returnEarly to true which is checked in XposedBridge, preventing the original method code from executing, as well as any other hooks on the method.
If you just want to access whatever the method was originally going to return then getResult() should do.
If you need to return anything else, you can use reflection or Xposed's helpers (findClass) to retrieve the l, k and j classes, replicate the code if needed, create a new instance and return it via setResult. Alternatively you can use a XC_MethodReplacement hook instead as you will likely replicate its functionality anyways.

adding parallell to a stream causes NullPointerException

I'm trying to get my head around Java streams. It was my understanding that they provide an easy way to parallellize behaviour, and that also not all operations benefit from parallellization, but that you always have the option to do it by just slapping .parallell() on to an existing stream. This might make the stream go slower in some cases, or return the elements in a different order at the end etc, but you always have the option to parallellize a stream. That's why I got confused when I changed this method:
public static List<Integer> primeSequence() {
List<Integer> list = new LinkedList<Integer>();
IntStream.range(1, 10)
.filter(x -> isPrime(x))
.forEach(list::add);
return list;
}
//returns {2,3,5,7}
to this:
public static List<Integer> primeSequence() {
List<Integer> list = new LinkedList<Integer>();
IntStream.range(1, 10).parallel()
.filter(x -> isPrime(x))
.forEach(list::add);
return list;
}
//throws NullPointerException();
I thought all streams were serial unless otherwise stated and parallel() just made then execute in parallel. What am I missing here? Why does it throw an Exception?
There is one significant issue with your initial primeSequence method implementation - you mix stream iteration with outer list modification. You should avoid using streams that way, otherwise you will face a lot of problems. Like the one you have described. If you take a look at how add(E element) method is implemented you will see something like this:
public boolean add(E e) {
this.linkLast(e);
return true;
}
void linkLast(E e) {
LinkedList.Node<E> l = this.last;
LinkedList.Node<E> newNode = new LinkedList.Node(l, e, (LinkedList.Node)null);
this.last = newNode;
if (l == null) {
this.first = newNode;
} else {
l.next = newNode;
}
++this.size;
++this.modCount;
}
If you use CopyOnWriteArrayList instead of a LinkedList in your example, there will be no NullPointerException thrown - only because CopyOnWriteArrayList uses locking for multithread execution synchronization:
public boolean add(E e) {
ReentrantLock lock = this.lock;
lock.lock();
boolean var6;
try {
Object[] elements = this.getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
this.setArray(newElements);
var6 = true;
} finally {
lock.unlock();
}
return var6;
}
But it is still not the best way to utilize parallel stream.
Correct way to use Stream API
Consider following modification to your code:
public static List<Integer> primeSequence() {
return IntStream.range(1, 10)
.parallel()
.filter(x -> isPrime(x))
.boxed()
.collect(Collectors.toList());
}
Instead of modifying some outer list (of any kind) we are collecting the result and return a final list. You can transform any list to a stream using .stream() method and you don't have to worry about initial list - all operation you will apply to that list won't modify the input and the result will be a copy of the input list.
I hope it helps.

Why java Map.merge does not pass a supplier?

I want in java a method which allows me to modify a value if exist, or insert one if it doesn't. Similar to merge, but:
I want to pass a value supplier and not a value, to avoid creating it when not needed
In case the value exists, I don't want to reinsert it nor remove it, just access its methods with a container.
I had to write this. The problem with writing it myself is that the version for Concurrent maps is not trivial
public static <K, V> V putOrConsume(Map<K, V> map, K key, Supplier<V> ifAbsent, Consumer<V> ifPresent) {
V val = map.get(key);
if (val != null) {
ifPresent.accept(val);
} else {
map.put(key, ifAbsent.get());
}
return val;
}
The best "standard" way of achieving it is to use compute():
Map<String, String> map = new HashMap<>();
BiFunction<String, String, String> convert = (k, v) -> v == null ? "new_" + k : "old_" + v;
map.compute("x", convert);
map.compute("x", convert);
System.out.println(map.get("x")); //prints old_new_x
Now, say, you have your Supplier and Consumer and would like to follow DRY principle. Then you could use a simple function combinator:
Map<String, String> map = new HashMap<>();
Supplier<String> ifAbsent = () -> "new";
Consumer<String> ifPresent = System.out::println;
BiFunction<String, String, String> putOrConsume = (k, v) -> {
if (v == null) return ifAbsent.get();
ifPresent.accept(v);
return v;
};
map.compute("x", putOrConsume); //nothing
map.compute("x", putOrConsume); //prints "new"
Obviously, you could write a combinator function that takes supplier and consumer and returns BiFunction to make the code above even more generic.
The drawback of this proposed approach is in the extra call to map.put() even if you simply consume the value, i.e. it will be slightly slower, by the time of key lookup. The good news are, map implementations will simply replace the value without creating the new node. I.e. no new objects will be created or garbage collected. Most of the time such trade-offs are justified.
map.compute(...) and map.putIfAbsent(...) are much more powerful than fairly specialized proposed putOrConsume(...). It is so asymmetrical I would actually review the reasons why you need it in the code.
You can achieve what you want with Map.compute and a trivial helper method, as well as with the help of a local class to know if your ifAbsent supplier has been used:
public static <K, V> V putOrConsume(
Map<K, V> map,
K key,
Supplier<V> ifAbsent,
Consumer<V> ifPresent) {
class AbsentSupplier implements Supplier<V> {
boolean used = false;
public V get() {
used = true;
return ifAbsent.get();
}
}
AbsentSupplier absentSupplier = new AbsentSupplier();
V computed = map.compute(
key,
(k, v) -> v == null ?
absentSupplier.get() :
consumeAndReturn(v, ifPresent));
return absentSupplier.used ? null : computed;
}
private static <V> V consumeAndReturn(V v, Consumer<V> consumer) {
consumer.accept(v);
return v;
}
The tricky part is finding whether you have used your ifAbsent supplier to return either null or the existent, consumed value.
The helper method simply adapts the ifPresent consumer so that it behaves like a unary operator that consumes the given value and returns it.
different from others answers, you also using Map.compute method and combine Functions with interface default methods / static methods to make your code more readable. for example:
Usage
//only consuming if value is present
Consumer<V> action = ...;
map.compute(key,ValueMapping.ifPresent(action));
//create value if value is absent
Supplier<V> supplier = ...;
map.compute(key,ValueMapping.ifPresent(action).orElse(supplier));
//map value from key if value is absent
Function<K,V> mapping = ...;
map.compute(key,ValueMapping.ifPresent(action).orElse(mapping));
//orElse supports short-circuit feature
map.compute(key,ValueMapping.ifPresent(action)
.orElse(supplier)
.orElse(() -> fail("it should not be called "+
"if the value computed by the previous orElse")));
<T> T fail(String message) {
throw new AssertionError(message);
}
ValueMapping
interface ValueMapping<T, R> extends BiFunction<T, R, R> {
default ValueMapping<T, R> orElse(Supplier<R> other) {
return orElse(k -> other.get());
}
default ValueMapping<T, R> orElse(Function<T, R> other) {
return (k, v) -> {
R result = this.apply(k, v);
return result!=null ? result : other.apply(k);
};
}
static <T, R> ValueMapping<T, R> ifPresent(Consumer<R> action) {
return (k, v) -> {
if (v!=null) {
action.accept(v);
}
return v;
};
}
}
Note
I used Objects.isNull in ValueMapping in previous version. and #Holger point out that is an overusing case, and should replacing it with simpler condition it != null.

Method reference does not fulfil the functional interface contract but it compile. How it is possible?

In the class below, I pass the method reference WordCounterEx::accumulate as second parameter to the reduce method. The signature of reduce method is:
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
Thus the second parameter of reduce method, must fulfil the BiFunction recipe.
But the passed accumulate method is not BiFunction (it has only one parameter). Why it still compile?
public class WordCounterEx {
private final int counter;
private final boolean lastSpace;
public WordCounterEx(int counter, boolean lastSpace) {
this.counter = counter;
this.lastSpace = lastSpace;
}
public int countWords(Stream<Character> stream) {
WordCounterEx wordCounter = stream.reduce(new WordCounterEx(0, true),
//HOW CAN THIS WORK? here must come BiFunction - R apply(T t, U u);
WordCounterEx::accumulate,
WordCounterEx::combine);
return wordCounter.counter;
}
public WordCounterEx accumulate(Character c) {
if(Character.isWhitespace(c)) {
return lastSpace ?
this :
new WordCounterEx(counter, true);
} else {
return lastSpace ?
new WordCounterEx(counter+1, false) :
this;
}
}
public WordCounterEx combine(WordCounterEx wordCounter) {
return new WordCounterEx(counter + wordCounter.counter
,wordCounter.lastSpace /*does not matter*/);
}
}
accumulate() is an instance method, and you refer to it by class name and method name (not by instance and method name). So if I wanted to call the method you are giving me, I would usually do myEx.accumulate(myCh). Thus I provide two things, the WordCounterEx instance and the character. Therefore, used this way the method counts as a BiFunction<WordCounterEx, ? super Character, WordCounterEx>.
If instead you had given me for example this::accumulate, the object to call the method on would have been given (this), and it could no longer be used as a BiFunction (in my Eclipse I get “The method reduce(U, BiFunction, BinaryOperator) in the type Stream is not applicable for the arguments (WordCounterEx, this::accumulate, WordCounterEx::combine)”).
The WordCounterEx#countWords method can be rewritten as follows:
public int countWordsWithInstance(Stream<Character> stream) {
WordCounterEx wordCounter = stream.reduce(new WordCounterEx(0, true),
this::accumulate,
WordCounterEx::combine);
return wordCounter.counter;
}
public WordCounterEx accumulate(WordCounterEx wc,Character c) {
if(Character.isWhitespace(c)) {
return wc.lastSpace ?
wc :
new WordCounterEx(wc.counter, true);
} else {
return wc.lastSpace ?
new WordCounterEx(wc.counter+1, false) :
wc;
}
}
In this case the accumulate method must have WordCounterEx wc in its signature

Partition/split/section IEnumerable<T> into IEnumerable<IEnumerable<T>> based on a function using LINQ?

I'd like to split a sequence in C# to a sequence of sequences using LINQ. I've done some investigation, and the closest SO article I've found that is slightly related is this.
However, this question only asks how to partition the original sequence based upon a constant value. I would like to partition my sequence based on an operation.
Specifically, I have a list of objects which contain a decimal property.
public class ExampleClass
{
public decimal TheValue { get; set; }
}
Let's say I have a sequence of ExampleClass, and the corresponding sequence of values of TheValue is:
{0,1,2,3,1,1,4,6,7,0,1,0,2,3,5,7,6,5,4,3,2,1}
I'd like to partition the original sequence into an IEnumerable<IEnumerable<ExampleClass>> with values of TheValue resembling:
{{0,1,2,3}, {1,1,4,6,7}, {0,1}, {0,2,3,5,7}, {6,5,4,3,2,1}}
I'm just lost on how this would be implemented. SO, can you help?
I have a seriously ugly solution right now, but have a "feeling" that LINQ will increase the elegance of my code.
Okay, I think we can do this...
public static IEnumerable<IEnumerable<TElement>>
PartitionMontonically<TElement, TKey>
(this IEnumerable<TElement> source,
Func<TElement, TKey> selector)
{
// TODO: Argument validation and custom comparisons
Comparer<TKey> keyComparer = Comparer<TKey>.Default;
using (var iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
{
yield break;
}
TKey currentKey = selector(iterator.Current);
List<TElement> currentList = new List<TElement> { iterator.Current };
int sign = 0;
while (iterator.MoveNext())
{
TElement element = iterator.Current;
TKey key = selector(element);
int nextSign = Math.Sign(keyComparer.Compare(currentKey, key));
// Haven't decided a direction yet
if (sign == 0)
{
sign = nextSign;
currentList.Add(element);
}
// Same direction or no change
else if (sign == nextSign || nextSign == 0)
{
currentList.Add(element);
}
else // Change in direction: yield current list and start a new one
{
yield return currentList;
currentList = new List<TElement> { element };
sign = 0;
}
currentKey = key;
}
yield return currentList;
}
}
Completely untested, but I think it might work...
alternatively with linq operators and some abuse of .net closures by reference.
public static IEnumerable<IEnumerable<T>> Monotonic<T>(this IEnumerable<T> enumerable)
{
var comparator = Comparer<T>.Default;
int i = 0;
T last = default(T);
return enumerable.GroupBy((value) => { i = comparator.Compare(value, last) > 0 ? i : i+1; last = value; return i; }).Select((group) => group.Select((_) => _));
}
Taken from some random utility code for partitioning IEnumerable's into a makeshift table for logging. If I recall properly, the odd ending Select is to prevent ambiguity when the input is an enumeration of strings.
Here's a custom LINQ operator which splits a sequence according to just about any criteria. Its parameters are:
xs: the input element sequence.
func: a function which accepts the "current" input element and a state object, and returns as a tuple:
a bool stating whether the input sequence should be split before the "current" element; and
a state object which will be passed to the next invocation of func.
initialState: the state object that gets passed to func on its first invocation.
Here it is, along with a helper class (required because yield return apparently cannot be nested):
public static IEnumerable<IEnumerable<T>> Split<T, TState>(
this IEnumerable<T> xs,
Func<T, TState, Tuple<bool, TState>> func,
TState initialState)
{
using (var splitter = new Splitter<T, TState>(xs, func, initialState))
{
while (splitter.HasNext)
{
yield return splitter.GetNext();
}
}
}
internal sealed class Splitter<T, TState> : IDisposable
{
public Splitter(IEnumerable<T> xs,
Func<T, TState, Tuple<bool, TState>> func,
TState initialState)
{
this.xs = xs.GetEnumerator();
this.func = func;
this.state = initialState;
this.hasNext = this.xs.MoveNext();
}
private readonly IEnumerator<T> xs;
private readonly Func<T, TState, Tuple<bool, TState>> func;
private bool hasNext;
private TState state;
public bool HasNext { get { return hasNext; } }
public IEnumerable<T> GetNext()
{
while (hasNext)
{
Tuple<bool, TState> decision = func(xs.Current, state);
state = decision.Item2;
if (decision.Item1) yield break;
yield return xs.Current;
hasNext = xs.MoveNext();
}
}
public void Dispose() { xs.Dispose(); }
}
Note: Here are some of the design decisions that went into the Split method:
It should make only a single pass over the sequence.
State is made explicit so that it's possible to keep side effects out of func.

Resources