Why have a cast in a compareTo(Object) - java

public int compareTo(Object x) {
Task other = (Task)x;
if (other.priority == this.priority) {
System.out.println("Each task has the same priority level.");
return 0;
} else if (other.priority > this.priority) {
System.out.println(other.priority + "\n" + this.priority);
return -1;
} else {
System.out.println(this.priority + "\n" + other.priority);
return 1;
}
}
That's the code I have for a programming assignment for class. I'm not sure why I use Task other = (Task)x; or what it's doing here. The rest I understand. If anyone has a quick explanation of what that's actually doing here I would be greatful. Thank you!

You are casting Object x to Task other - Object and Task are different types, so you need the cast so you can treat x as the expected type (and get to it's fields).
Normally in compareTo() you would first have something like if (x instanceof Task) before blindly casting it - if you don't and the types are different then things will crash)

The method signature takes an Object type object so in order to reference the variable priority within the object passed in, it has to do a cast to the Task object as the variable only exists within the Task class.
Personally though, I would think this was bad practice as you do not know what sort of object is being passed in (any class subclassing Object can be passed in) so a instance of check would not go amiss less you want to run into a runtime error of a ClassCastException.
Alternatively, you could use generics to specify what sort of object you want to compare to. So rather than doing this...
public class Task implements Comparable {
private int priority = 1;
#Override
public int compareTo(Object o) {
if (o instanceof Task) {
Task t = (Task) o;
return this.priority < t.priority;
}
return -1;
}
}
...you could do this...
public class Task implements Comparable<Task> {
private int priority = 1;
#Override
public int compareTo(Task t) {
return this.priority < t.priority;
}
}

Related

How to sort sortedset by value that can be duplicate?

In Java 1.7, I have a "Post class" that has the Post ID and the number of votes of every Post. I want to create sorted set of Posts that can be always sorted by the number of votes. Please be informed that different Posts can have the same number of votes.
The problem is that when I create 2 different Posts with 2 different IDs and different number of votes, the sorted set detects that they are different Posts and thus add them twice instead of replacing the existing thread with the number of new votes. The example below
Post Class:
public class Post implements Comparable<Post> {
protected int id;
protected int votes;
public Post(int id) {
this.id = id;
this.votes = 0;
}
public Post(int id, int votes) {
this.id = id;
this.votes = votes;
}
#Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
Post post= (Post) o;
return id == employee.id;
}
#Override
public int hashCode() {
return Objects.hash(this.id);
}
#Override
public int compareTo(Post t) {
int diff = ((Integer) t.votes).compareTo(this.votes);
if (diff == 0) {
return ((Integer) t.id).compareTo(this.id);
}
return diff;
}
}
Run Method:
public void run() {
SortedSet<Post> set = new TreeSet<Post>();
Post t1 = new Post(1, 30);
Post t2 = new Post(1, 40);
Post t3 = new Post(2, 100);
set.add(t1);
set.add(t2);
set.add(t3);
for (Post t : set) {
System.err.println(t.id + " >> " + t.votes);
}
}
Expected Output:
2 >> 100
1 >> 40
Actual Output
2 >> 100
1 >> 40
1 >> 30
As you can see the problem is that the same Post appeared twice in the set which is not the desired output.
I also tried to avoid using Comparable interface and instead I used Comparator, yet, I got the same result.
Comparator Class:
class CompareByVotes implements Comparator<Post> {
#Override
public int compare(Post t1, Post t2) {
int diff = ((Integer) t2.votes).compareTo(t1.votes);
if (diff == 0) {
return ((Integer) t2.id).compareTo(t1.id);
}
return diff;
}
}
Question:
Any changes required to get it work as desired ?
Your compareTo() method doesn't return 0 when the objects you compare are equal based on the equals() method. However, this is required by the SortedSet interface:
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 your compareTo() method must return 0 when they are equal. One possible solution would be something like this:
public int compareTo(Post t) {
if (equals(t)) {
return 0;
}
int diff = ((Integer) t.votes).compareTo(this.votes);
if (diff == 0) {
return ((Integer) t.id).compareTo(this.id);
}
return diff;
}
Also, keep in mind that add() does not "overwrite" the object, when an equal object is already in the set. See the documentation of add():
[...] If this set already contains the element, the call leaves the set unchanged and returns false.

Removing specific element from ArrayList

I need help with removing just added element from the arrayList.
I have a private static ArrayList<Position> positions = new ArrayList<>() to which I'm adding objects of the class Position with parameters name, quantity, and price.
Than I have a method adding objects to the list, and in case if the same product is added for the second time, it is supposed to add the quantity to the first object of that name and remove that second one.
So far I have this method:
public void addPosition(Position p) {
for (Position poz: positions) {
if (poz.getname().equals(p.getname())) {
poz.setquantity(poz.getquantity() + p.getquantity());
}
} positions.add(p);
}
Adding quantities works just fine, but I've got problem with removing the element with recurring name.
Please help.
You shouldn't add duplicate items and then remove them. Just declare a method which handles adding items correctly; that is, it adds the item if it does not exist, and it updates the quantity if it does exist.
It should look like this:
public void addPosition(Position addition) {
//flag to track whether the new item exists in the list
boolean itemExists = false;
//go through the list looking for an item with the passed name to update
for (Position existing : positions) {
if (existing.getName().equals(addition.getName())) {
existing.setQuantity(existing.getQuantity() + addition.getQuantity());
itemExists = true;
}
}
//if no matching item was found, add the new item
if (!itemExists) {
positions.add(addition);
}
}
The above should work. If you care about performance, it might be better to use a HashMap so you can look up the Position by name instead of looping through the whole list each time.
If you are interested to know other data Structure , i want suggest you HashSet , by default it will not insert duplicates for primitive objects .
In your case the only thing you need to do to your Position class , is to add
equals and hashCode methods . As getters and setters Eclipse for example will create by him self .
hashCode()
As you know this method provides the has code of an object. Basically the default implementation of hashCode() provided by Object is derived by mapping the memory address to an integer value. If look into the source of Object class , you will find the following code for the hashCode. public native int hashCode(); It indicates that hashCode is the native implementation which provides the memory address to a certain extent. However it is possible to override the hashCode method in your implementation class.
equals()
This particular method is used to make equal comparison between two objects. There are two types of comparisons in Java. One is using “= =” operator and another is “equals()”. I hope that you know the difference between this two. More specifically the “.equals()” refers to equivalence relations. So in broad sense you say that two objects are equivalent they satisfy the “equals()” condition. If you look into the source code of Object class you will find the following code for the equals() method.
Here a complete working example ( you can modify your class following this cose)
import java.util.HashSet;
public class Zhashset{
private int num;
public Zhashset(){
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + num;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Zhashset other = (Zhashset) obj;
if (num != other.num)
return false;
return true;
}
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
HashSet<Zhashset> hs = new HashSet<Zhashset>();
hs.add(new Zhashset());
hs.add(new Zhashset());
for(Zhashset item : hs)
System.out.println(item.getNum());
}
}
Output will be : 0 written only once.

Thread safe of operation in one entry

I want to do operations like
class A {
}
ConcurrentHashMap<A, Integer> map = new ConcurrentHashMap<>();
public void fun() {
Integer count = map.get(Object);
if (count != null) {
map.put(Object, count+1);
}
}
public void add() {
// increase Object count by 1
}
public void remove() {
// deduct Object count by 1
}
How can I make fun() thread safe ?
I know a way to do this is to add synchronized block
public void fun() {
synchronized("") {
Integer count = map.get(Object);
if (count != null) {
map.put(Object, count+1);
}
}
}
But are there any other ways to do it ?
Or are there any libraries to do it ?
like thread safe entry processor ?
I also want to implement something like
public void remove() {
int count = map.get(Object);
count -= 5;
if (count <= 0) {
map.remove(Object);
} else {
map.put(Object, count + 2);
}
}
Any ways to do this ?
Thank you
Use AtomicInteger and ConcurrentHashMap.putIfAbsent()
Also look at the
ConcurrentHashMap.remove(key, value) -- removes the key only if it is mapped to the given value.
I am not sure, if it is possible to implement the exact logic (which is not very well defined in the question above), but those methods could be very useful in doing something similar.
More hints (that could be useful or may be not too much):
You (probably!) can use methods: computeIfAbsent, computeIfPresent (or replace), and remove(key, value).
ConcurrentHashMap could be defined on values are Integers.
It will be very dirty solution, and I do not recommend you to use it, but as something to think about, it could be very challenging.
Let me know if you need more hints.

Method Enum isBigger()

I am trying to write a method in a Java enum: isBigger(Valoration val), which returns true if if the current rating is bigger than one that is passed as parameter throwing the exception ValorationNoValued if the valuations
compared (or both) is NO_VALUED.
public enum Valoracion {
NO_VALUED(0),
SO_BAD(0),
BAD(2),
OK(4),
GOOD(6),
EXCELENT(8),
WOW(10);
....
public boolean isBigger(Valoration val) throws ValorationNoValued {
if (val == NO_VALUED) {
throw new ValorationNoValued("message");
}
else {
return val.getValor() > this.valor;
}
}
}
I want to know if the current rating is NO_VALUED, but I don't know how.
You can always refer the the “current object” via this be it an enum or not. But…
It seems, your enum has a method getValor() to return the numerical value. Then it would be much cleaner to intercept the exceptional state there rather than in the comparison method:
public enum Valoracion {
NO_VALUED (0) {
#Override int getValor() {
throw new ValorationNoValued("message");
}
},
SO_BAD (0),
BAD(2),
OK (4),
GOOD (6),
EXCELENT (8),
WOW (10);
....
int getValor() {
return valorValue;
}
public boolean isBigger(Valoration val) throws ValorationNoValued {
return val.getValor()>this.getValor();
}
This way, no conditionals are needed and the symmetry between a.isBigger(b) and b.isBigger(a) comes for free.
If you prefer conditionals over overriding the method, you may still implement the getValor() method as
int getValor() {
if(this==NO_VALUED) throw new ValorationNoValued("message");
return valorValue;
}
without the need to care for two sides in the isBigger method.
Compare this:
If (this == NO_VALUED) {

Homemade Stack Equals method

For my data structures class, we have to create our own Stack data type and the implementation for it as a project. The problem I'm running into is when the professor asked us to implement an equals(Object object) method. Heres what I have so far...
package stack;
import list.*;
public class Stack <E>
implements StackADT<E>//the interface
{
List <E> values;
public Stack()
{
values = new ArrayList<E>();
}
public E push(E value)
{
values.add(value);
return value;
}
public E pop()
{
return values.remove(values.size()-1);
}
public E peek()
{
return values.get(values.size()-1);
}
/** #return true only if this Stack is empty */
public boolean isEmpty()
{
return (values.size()==0);
}
/** Clear this stack, to make it an empty stack */
public void clear()
{
for (int i = 0; i < values.size()-1; i++)
{
pop();
}
}
public String toString()
{
String result = "[";
for (int i = 0; i<values.size(); i++)
{
if (i == values.size()-1)
{
result = result + values.get(i);
}
else
{
result = result + values.get(i) +",";
}
}
result = result + "]";
return result;
}
public boolean equals (Object object)
{
if (!(object instanceof StackADT))
{
return false;
}
StackADT <E> otherStack = new Stack<E>();
for(Object o: object)//heres where i run into trouble
{
otherStack.push(o);
}
for (int i=0;i<values.size()-1;i++)
{
if (!(values.get(i).equals(otherStack.pop())))
{
return false;
}
}
return true;
}
}
Our Stack is pretty much an ArrayList which we also built in our class. the problem is, I cant add the Object object into a stack because its not something thats iteratable(?able to be iterated over). Is there a better way to do this? I would think a get() would work, since the Stack I create is an ArrayList, but whenever I use get() on otherStack, it can't find the method. I had a temporary solution when I tried casting object as a stack(I hope im using the right terminology). It looked something like this
Stack otherStack = (Stack) object;
for (int i=0;i<values.size()-1;i++)
{
if (!(values.get(i).equals(otherStack.pop())))
{
return false;
}
}
return true;
}
this seemed to work, but when pop() was called on otherStack, the values in the original list(the one that becomes otherStack) that was passed into the equals() method we're also popped from the original list, leading to an incorrect result. Is there a better way to do this without adding in any other methods? I'm trying to stick as close to the formula set up by my professor as possible, so I dont want to add any extra fields or methods.
any and all help is appreciated
An equals method is not supposed to create anything, not even a temporary object. Rather than creating a new otherStack, cast the object that you have checked to be StackADT, like this:
// This should be the first line of any equals() implementation:
if (object == this) {
return true;
}
// You've got this part right: you need to check the other object's type
if (!(object instanceof StackADT)) {
return false;
}
// Now that you know the type, cast the other object to StackADT<E>
StackADT<E> otherStack = (StackADT<E>)object;
// The next step is to check the sizes:
if (values.size() != otherStack.values.size()) {
return false;
}
// Finally, go through the individual elements in a loop
In the loop that follows, do not pop the other stack. Do not do anything that can modify it. Simply go through the underlying storage (i.e. values), and check elements one by one.
Don't forget to override hashCode as well: you need to do it every time when you override equals for the object to fulfill the contract specified by java.lang.Object.

Categories