Check if HashMap was modified (values added or modified) - java

I have a method that iterates over the HashMap to get the total integer number of all of the values. I would like to avoid iterating over the entire map and finding the sum if the HashMap wasn't changed since the last time this method was called on.
How do I check whether new values or old values were modified in a HashMap? Is there such a way?

Extend HashMap; override the methods that change values, and set a flag indicating that some value has changed. Provide a method to test this value, and probably one to reset it. Think about concurrency if it's an issue in your application.
(I am trusting that you understand how to extend a class, and that overriding the methods does not mean that you have to reimplement all of them (super is your friend). This whole class doesn't seem to me, at first glance, to be more than 30-40 lines of code.)

I add a new answer that will not be affected by clock work-around:
public class YourMap<K, V> extends HashMap<K, V> {
private int state = 0;
public YourMap() {
super();
}
#Override
public V put(K key, V value) {
state++;
return super.put(key, value);
}
public boolean isUpdated(int state) {
return (state < this.state);
}
public int getState() {
return state;
}
... // Do the same with clear, remove... methods.
}
Then in your code:
public static void Main() {
new YourMap<Integer, Integer> myMap = new YourMap<Integer, Integer>();
int state = myMap.getState();
myMap.put(1, 2);
System.out.println(myMap.isUpdated(state)); // will print true.
if (!myMap.isUpdated()) { // in this demo, it will never go in this if.
// call your process...
}
}
This one is efficient and you will not have problems you should have with currentTimeMilliseconds.

Related

assertThat field by field or compare object

I'm having an argument with my friend and I would like to know your opinion.
In a test do you think that is better to compare field by field or just create a expectedResultObject and compare it.
For instance:
Assert.That(obj.Foo).isEqualTo(FOO);
Assert.That(obj.Test).isEqualTo(TEST);
vs
Foo expected = new Foo(FOO, TEST);
assertThat(obj).usingRecursiveComparison().isEqualTo(expected);
In this example we only have two fields but we can have allot more.
Thanks
If you can have multiple fields, the expected method is better because you'll be adding the other fields inside the constructors' params. Imagine if you have 100 fields, adding them line by line as you suggested in your first example would be a headache, while adding in the params would be a bit simpler.
Between the two possibilities, I prefer the one without the usingRecursiveComparison().
I wanted to add a few thins :
An object is not a data toolbox, so it's not a good thing to add getter/setter to test your object's creation. It's better test a behaviour, a method where you can test the return.
Generally I'm not fond of writing more than one assertion in a test.
There is a technique which made assertions more lisibles (with AssertJ but I think you can make this kind of thing with Hamcrest).
The initial class :
public class Amount {
private int value;
public Integer add(int amountToAdd) {
value += amountToAdd;
return value;
}
}
Create an Asserter :
public class IntegerAsserter extends org.assertj.core.api.AbstractAssert<IntegerAsserter, Integer> {
IntegerAsserter(Integer actual) {
super(IntegerAsserter.class, actual);
}
public IntegerAsserter isBetweenOneOrTwo() {
Assert.assertTrue(actual < 2);
Assert.assertTrue(actual > 1);
return this;
}
}
Create a new Assertions :
public class Assertions extends org.fest.assertions.Assertions {
public static IntegerAsserter assertThat(Integer actual) {
return new IntegerAsserter(actual);
}
}
And then use it :
public void should_be_between_one_or_two {
Amount amount = new Amount(0);
Integer newAmount = amount.add(1);
Assertions.assertThat(obj).isBetweenOneOrTwo();
}

Duplicate items added in ConcurrentSkipListSet

I am trying to maintain insertion order in ConcurrentSkipListSet. The item being added is a custom class type with value(String) and index (int) properties. It implements Comparable interface. The set behaves very inconsistently, sometimes adding duplicate items. Items are considered duplicate if they have same value.
// This is the Item class being added in the set.
final class Item implements Comparable<Item> {
private String value;
private int index;
Item(String val, int idx) {
this.value = val;
this.index = idx;
}
#Override
public int compareTo(Item o) {
// returns zero when values are equal indicating it's a duplicate item.
return this.value.equals(o.value) ? 0 : this.index - o.index;
}
#Override
public String toString() {
return this.value;
}
}
// Below is the main class.
public class Test {
ConcurrentSkipListSet<Item> set;
AtomicInteger index;
public Test() {
set = new ConcurrentSkipListSet<>();
index = new AtomicInteger(0);
}
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
Test test = new Test();
test.addItems();
test.assertItems();
}
}
//trying to test it for 10 times. It always fails for once or twice.
private void assertItems() {
Iterator<Item> iterator = set.iterator();
String[] values = {"yyyy", "bbbb", "aaaa"};
for (String value : values) {
if (!value.equals(iterator.next().toString())) {
System.out.println("failed for :" + set);
return;
}
}
System.out.println("passed for :" + set);
}
//adding items with some duplicate values
private void addItems() {
set.add(new Item("yyyy", index.getAndIncrement()));
set.add(new Item("bbbb", index.getAndIncrement()));
set.add(new Item("yyyy", index.getAndIncrement()));
set.add(new Item("aaaa", index.getAndIncrement()));
}
Expected : passed for :[yyyy, bbbb, aaaa]
Actual : failed for :[yyyy, bbbb, yyyy, aaaa]
But as mentioned before, the result is very inconsistent. Most of the times, it passes.
Please let know what could be the reason for this behavior. Is the 'compareTo()' method wrong? If so, it should always fail.
Ideally we should override 'equals()' method also. But it doesn't matter from sorted set perspective.
Appreciate your help.
You have broken the contract of compareTo, which results in undefined behaviour.
Finally, the implementor must ensure that x.compareTo(y)==0 implies
that sgn(x.compareTo(z)) == sgn(y.compareTo(z)), for all z.
You can easily see that you fail this requirement by pulling your Items out into variables:
final Item x = new Item("yyyy", index.getAndIncrement());
final Item z = new Item("bbbb", index.getAndIncrement());
final Item y = new Item("yyyy", index.getAndIncrement());
System.out.println(x.compareTo(y));
System.out.println(x.compareTo(z));
System.out.println(y.compareTo(z));
Output:
0
-1
1
The signs are different, therefore the contract has been broken.
In your compareTo-implementation you are mixing two different properties in an illegal way. Thus you break the contract of the Comparable interface.
In your comparison, you look at the index only if the values are not equal. This way you do not define an overall natural order for your items. Depending on what comparison is done first, the result of sorting a list will be random.
#Override
public int compareTo(Item o) {
int vCompare = this.value.compareTo(o.value);
if (vCompare == 0) {
return this.index - o.index;
}
return vCompare;
}
This implementation will first compare by value and then by index. It adheres to the Comparable contract and actually defines a natural order for Items and works fine with the Set implementation.
Caution: This sample implementation will break the tests.
The tests are there to show the code behaves as intended. But in this case the intended behavior is the actual issue.
It is incompatible with the Comparable contract.
You cannot sort a list by numeric index and expect a lookup by alphabetical value to succeed. But that's exactly what is attempted here. Sort by index but find duplicate names. It does not work this way.
I don't know the implementation of ConcurrentSkipListSet in detail, but it looks like you need to override the equals method of your class to specify what qualifies two objects to be equal.
This is not an answer, rather a solution to achieve the objective based on root cause finding by #Michael and #Jochen. Modified the Item class comparator to below to have natural order of value String.
public int compareTo(Item o) {
return this.value.compareTo(o.value);
}
And then, added an index based comparator to achieve FIFO retrieval.
// This iterator would now be used in assertItems() method in main class.
private Iterator<Item> getFIFOIterator() {
ArrayList<Item> list = new ArrayList<>(set);
list.sort(Comparator.comparingInt(Item::getIndex));
return list.iterator();
}
#Michael and #Jochen : Appreciate you for taking your time and figuring out the root cause.

Immutable keys - fixed length map in Java

Is there a way in Java to create a collection (map) with fixed size and length?
I.e., I would like to initialize it with K constant keys (e.g. strings) but still want to be able to change the values.
Edit:
The test case has a fixed number of objects, each one corresponds to a number (float). Each time a specific event in the application occurs, I would like to multiply all the numbers in the collection, except the number that corresponds to the object that "caused" the event.
The number is not logically an attribiute of the object.
I suggest you first look at Mike's answer to get an idea of how to go about solving this problem, then make some changes to the code he provided so it will work in your situation:
import java.util.HashMap;
public class InstrumentedHashMap<K> extends HashMap<K, Float> {
private static final long serialVersionUID = 1L;
private int MAX;
public InstrumentedHashMap(int capacity) {
super();
MAX = capacity;
}
#Override
public Float put(K key, Float value) {
if (super.size() >= MAX && !super.containsKey(key)) {
return null;
} else {
super.put(key, value);
return value;
}
}
public void event(K trigger, int multiplyAmount, float subtractAmount) {
super.entrySet().stream().forEach(e -> {
if (!e.getKey().equals(trigger))
e.setValue(e.getValue() * multiplyAmount);
else
e.setValue(e.getValue() - subtractAmount);
});
}
}
You can use the InstrumentedHashMap#event method to handle your "specific event", with the multiplyAmount parameter being the value that you want to multiply your floats by.

Removing key from Map in case of Atomic Values

I want to remove keys from map in case if the value for the key is zero(0) i am able to achieve it using map.values().removeAll(Collections.singleton(0l));.
It was working nice till i was using Map<String,Long> but now we have changed the implementation to Map<String,AtomicLong> now it dosen't remove the keys whose values are zero since i am using an Atomic variable as value.
Small code snippet on which i tried ::
Map<String, AtomicLong> atomicMap = new HashMap<String,AtomicLong>();
atomicMap.put("Ron", new AtomicLong(0l));
atomicMap.put("David", new AtomicLong(0l));
atomicMap.put("Fredrick", new AtomicLong(0l));
atomicMap.put("Gema", new AtomicLong(1l));
atomicMap.put("Andrew", new AtomicLong(1l));
atomicMap.values().removeAll(Collections.singleton(new AtomicLong(0l)));
System.out.println(atomicMap.toString());
which outputs as {Ron=0, Fredrick=0, Gema=1, Andrew=1, David=0}
as you can see the keys which have values 0 are not being removed. Can anyone suggest a solution over this , it will be of great help.
Thanks.
If you are using Java8, there is a removeIf method that you could use.
atomicMap.values().removeIf(x -> x.get() == 0L);
// Prints {Gema=1, Andrew=1}
Two instances of AtomicLong are never equal. If you look at AtomicLong you can see that it never overrides the equal() method. See Why are two AtomicIntegers never equal?
You can overcome this with your own custom AtomicLong implementation, which implements equals() and make your strategy to remove the elements work.
public class MyAtomicLongExample {
static class MyAtomicLong extends AtomicLong {
private static final long serialVersionUID = -8694980851332228839L;
public MyAtomicLong(long initialValue) {
super(initialValue);
}
#Override
public boolean equals(Object obj) {
return obj instanceof MyAtomicLong && ((MyAtomicLong) obj).get() == get();
}
}
public static void main(String[] args) {
Map<String, MyAtomicLong> atomicMap = new HashMap<>();
atomicMap.put("Ron", new MyAtomicLong(0l));
atomicMap.put("David", new MyAtomicLong(0l));
atomicMap.put("Fredrick", new MyAtomicLong(0l));
atomicMap.put("Gema", new MyAtomicLong(1l));
atomicMap.put("Andrew", new MyAtomicLong(1l));
atomicMap.values().removeAll(Collections.singleton(new MyAtomicLong(0l)));
System.out.println(atomicMap);
}
}
This will print {Gema=1, Andrew=1}
Incase if you want to compute then decide to remove when value is zero.
if (atomicMap.compute("Andrew", (k, v) -> v.decrementAndGet()) == 0) {
atomicMap.remove("Andrew");
}

Is it possible to loop setters and getters?

I'm fairly confident that there's no way this could work, but I wanted to ask anyway just in case I'm wrong:
I've heard many times that whenever you have a certain number of lines of very similar code in one batch, you should always loop through them.
So say I have something like the following.
setPos1(getCard1());
setPos2(getCard2());
setPos3(getCard3());
setPos4(getCard4());
setPos5(getCard5());
setPos6(getCard6());
setPos7(getCard7());
setPos8(getCard8());
setPos9(getCard9());
setPos10(getCard10());
setPos11(getCard11());
setPos12(getCard12());
There is no way to cut down on lines of code as, e.g., below, right?
for (i = 0; i < 12; i++) {
setPos + i(getCard + i)());
}
I'm sure this will have been asked before somewhere, but neither Google nor SO Search turned up with a negative proof.
Thanks for quickly confirming this!
No way to do that specifically in Java without reflection, and I don't think it would be worth it. This looks more like a cue that you should refactor your getcard function to take an integer argument. Then you could loop.
This is a simple snippet that shows how to loop through the getters of a certain object to check if the returned values are null, using reflection:
for (Method m : myObj.getClass().getMethods()) {
// The getter should start with "get"
// I ignore getClass() method because it never returns null
if (m.getName().startsWith("get") && !m.getName().equals("getClass")) {
// These getters have no arguments
if (m.invoke(myObj) == null) {
// Do something
}
}
}
Like the others stated, probably it's not an elegant implementation. It's just for the sake of completeness.
You could do it via reflection, but it would be cumbersome. A better approach might be to make generic setPos() and getCard() methods into which you could pass the index of the current item.
You need to ditch the getter/setter pairs, and use a List to store your objects rather then trying to stuff everything into one God object.
Here's a contrived example:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Foo {
public static class Card {
int val;
public Card(int val) {
this.val = val;
}
public int getVal() {
return val;
}
}
public static class Position {
int value;
public Position(Card card) {
this.value = card.getVal();
}
}
public static void main(String[] args) {
List<Card> cards = new ArrayList<Card>(Arrays.asList(new Card(1), new Card(2), new Card(3)));
List<Position> positions = new ArrayList<Position>();
for (Card card : cards) {
positions.add(new Position(card));
}
}
}
You can't dynamically construct a method name and then invoke it (without reflection). Even with reflection it would be a bit brittle.
One option is to lump all those operations into one method like setAllPositions and just call that method.
Alternatively, you could have an array of positions, and then just loop over the array, setting the value at each index.
Card[] cardsAtPosition = new Card[12];
and then something like
public void setCardsAtEachPosition(Card[] valuesToSet) {
// check to make sure valuesToSet has the required number of cards
for (i = 0; i < cardsAtPosition.length; i++) {
cardsAtPosition[i] = valuesToSet[i];
}
}
Reflection would be your only option for your example case.

Categories