I got a class used in an Android app, which is declared like this:
public static class MyData implements Comparable<MyData>
{
public MyEnum myEnum;
#Override
public int compareTo(MyData another)
{
if(this.myEnum.equals(MyEnum.Value1))
{
return 1;
}
if(another.myEnum.equals(MyEnum.Value1))
{
return -1;
}
if(this.myEnum.equals(MyEnum.Value2))
{
return 1;
}
if(another.myEnum.equals(MyEnum.Value2))
{
return -1;
}
return 0;
}
}
I defined a list: List<MyData> myList = new LinkedList<MyData>();
After adding items to the list I call: Collections.sort(myList)
The problem is that when I debug, I see the compareTo method being called after the sort method is invoked, however it doesn't enter the first if even that it should. I even put the Boolean expression in Eclipse in the "Expressions" view and it returned true, but the code simply jumps to the return 0; and the list is not being sorted like I want to.
Why is that?
Eventually I changed that enum class member to an int member which was initialized with the ordinal value inside the Enum.
Then the compareTo method was changed like this:
#Override
public int compareTo(MyData another)
{
Integer myVal = this.intVal;
Integer otherVal = another.intVal;
return myVal.compareTo(otherVal);
}
Related
I am hard stuck on a problem I cannot find a good answer to. I've found
this one about custom comparators, but it is incomplete:
class YourClass {
static Comparator<YourClass> getAttribute1Comparator() {
return new Comparator<YourClass>() {
// compare using attribute 1
};
}
static Comparator<YourClass> getAttribute2Comparator() {
return new Comparator<YourClass>() {
// compare using attribute 2
};
}
}
That should work, but I don't know how the comparison part works. Here is my class:
package ZVCVolkel_Logic;
import java.util.Comparator;
public class Vliegtuig implements Comparator<Vliegtuig>{
private String naam;
private String type;
private String status;
private Hangaar hangaar;
public Vliegtuig(String naam, String type, String status, Hangaar hangaar){
this.naam = naam;
this.type = type;
this.status = status;
this.hangaar = hangaar;
}
}
Now I need a comparator for status and for Hangaar.getName(). Can someone help?
It is not the one, he has only 1 comparator. I can get that working too but not with 2 different ones in 1 class.
The comparator interface has a method compare return an int value to determine the relation ship between two objects.
It will return:
a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
static Comparator<Vliegtuig> hangaarNameComparator() {
return new Comparator<Vliegtuig>(){
public int compare(Vliegtuig one, Vliegtuig two) {
return one.getHangaar().getName().compareTo(two.getHangaar().getName());
}
}
}
Here you probably want to take care of NullPointerException if getHangaar() or hangaar.getName() return null.
In java 8 you could do this:
Comparator<Vliegtuig> hangaarNameComparator = Comparator.comparing(Vliegtuig::getHagaar,
Comparator.comparing(Hagaar::getName));
In the comparator implementation you need to compare 2 objects. You can refer to most of JDK classes for example, for instance java.lang.Integer.
In your case solution will be to use embedded compactors from objects like this:
Comparator<Vliegtuig> nameComparator = new Comparator<>() {
#Override
public int compare(Vliegtuig o1, Vliegtuig o2) {
return o1.getName().compareTo(o2.getName());
}
}
And you don't need to extend Comparator by the Vliegtuig.
I am trying to convert this data type to call out the method later on in another class to switch around layouts being made in other methods such as recipe1Layout(); by the index number of a class that has a field of a Class<?> Array.
Here is the getItem() method
public int getItem(){
int index = 0;
for(int i = 0; i < 100; i++) {
try{
index = recipe.getClass().getField("Classes").get(i);
} catch(Exception e){
}
}
return index;
}
Here is the Recipe Class
public class Recipes {
public Class<?>[] Classes = {
ChileConLecheActivity.class,
ArrozActivity.class,
EnchiladasActivity.class,
SopaActivity.class
};
}
The type of Class needs to be here because I have other uses for the recipe class.
For example, making a new instance of all classes to later on be called out to make adjustments to all the classes with one method.
The only thing I can think of is converting the type Class to an int so I can call out the method returning the index number I can do something like recipe.
index = Integer.parseInt(Classes[I].getName().toString());
But this is where I am asking for help I have no idea how to get rid of the error in the logcat.
The error shows up as
IndexOutOfArrayException
First off, stop using reflection. Use a public static array.
public class Recipes {
public static final Class<?>[] CLASSES = {
ChileConLecheActivity.class,
ArrozActivity.class,
EnchiladasActivity.class,
SopaActivity.class
};
}
Then, assuming your recipe instance has a field of what Class<Activity> it is assigned to, then, you would want something like this
public int getItem(){
int index = -1;
for(int i = 0 ; i < Recipe.CLASSES.length; i++) {
if (recipe.getActivityClass().equals(Recipe.CLASSES[i]) {
index = i;
break;
}
}
return index;
}
However, under certain situations, coupling one Activity class to any single Recipe instance, probably isn't a good idea.
I am trying to convert this data type to call out the method later on in another class to switch around layouts being made in other methods
if I understand what you are trying to do, you want a some mapping structure to some classes which have some pre-defined layouts.
Generally, this can be done with enums and OOP patterns
Have some base classes like this
public interface Layoutable {
int getLayout();
}
public enum Recipe {
ChileConLeche(R.layout.chile_con_leche),
Arroz(R.layout.arroz),
Enchiladas(R.layout.enchiladas),
Sopa(R.layout.sopa)
int layout;
Recipe(int layout) { this.layout = layout };
}
Ideally, you would want to use Fragments, but here is an example of an Activity structure
public abstract class RecipeActvity extends AppCompatActivity implements Layoutable {
protected Recipe recipe;
protected int getLayout() { return recipe.layout; }
}
public class ChileConLecheActivity extends RecipeActvity {
public ChileConLecheActivity() {
this.recipe = Recipe.ChileConLeche;
}
#Override
public void onCreate(...) {
setContentView(getLayout());
}
}
You can also combine this with a Map<Recipe, Class<RecipeActivity>>, from which you would use map.get(Recipe.ChileConCarne) to get the respective class element, for which you can startActivity() with
Just trying to run through some code for an assignment I'm doing. It is probably simple but for the life of me I can't figure out why I get the above error at the first line
(public WaterLog.......).
Later I want to pass it this line:
[ log = new WaterLog(8, damCapacity); ]
Any help would be appreciated, I am new to this sorry.
public class WaterLog(Integer windowSize, Integer maxEntry) {
private Integer size = windowSize;
private Integer max = maxEntry;
private ArrayList theLog(int windowSize);
private int counter = 0;
public void addEntry(Integer newEntry) throws SimulationException {
theLog.add(0, newEntry);
counter++;
}
public Integer getEntry(Integer index) throws SimulationException {
If (thelog.isEmpty() || thelog.size() < index) {
return null;
}
return thelog.get(index);
}
public Integer variation() throws SimulationException {
int old, recent = 0;
recent = thelog.get(0);
old = thelog.get(thelog.size-1);
return recent-old;
}
public Integer numEntries() {
return counter;
}
}
Assuming SimulationException is defined correctly:
class WaterLog{
private Integer size;
private Integer max ;
private ArrayList<Integer> theLog; //parameterize your lists
private int counter = 0;
public WaterLog(Integer windowSize, Integer maxEntry) //this is the behavior you were looking for
{
this.size = windowSize;
this.max = maxEntry;
theLog = new ArrayList<Integer>(windowSize);
}
public void addEntry(Integer newEntry) throws SimulationException {
theLog.add(0, newEntry);
counter++;
}
public Integer getEntry(Integer index) throws SimulationException {
if (theLog.isEmpty() || theLog.size() < index) { //Java is case sensitive
return null;
}
return theLog.get(index);
}
public Integer variation() throws SimulationException {
int old, recent = 0;
recent = theLog.get(0);
old = theLog.get(theLog.size()-1); //again, watch case, also size is a method
return recent-old;
}
public Integer numEntries() {
return counter;
}
}
See the comments I added.
EDIT: To explain a bit further what was going on, let's take a look at what you were doing.
public class WaterLog(Integer windowSize, Integer maxEntry) {
private Integer size = windowSize;
private Integer max = maxEntry;
private ArrayList theLog(int windowSize);
private int counter = 0;
You seem to have confused a class with a constructor. The variables you defined were attributes, which was correct. You needed to use the syntax I showed in my answer to create a constructor. For that same reason, you don't have access to variables like windowSize. To remedy this, we allow them to still be defined outside the constructor, but assigned values inside it, where we have access to windowSize and maxEntry.
If you want to pass some parameters to this class you need a constructor. By default Each and EVERY class comes with a default constructor - which is there, you just don't see it ( but can declare it). What you can then do is make an overloaded construcotr ( which takes some arguments ) and this is what you want so..
if you have a class
class WaterLog {
// no constructor
}
the above is really a
class WaterLog {
public WaterLog() {
// this is the constructor - if you do not declare it its still here, you just dont see it. Ofcourse you have option to declare it.
}
}
The overloaded constructor is something like this
class WaterLog {
public WaterLog() {
//default constructor
}
public WaterLog(Integer int, String string, etc...) {
//overloaded constructor
}
}
and the above is what you need in order to pass arguments to this class constructor. I am not briliant at explaining things but if you need more clarification just let me know :)
To compare the different objects of the same class with their contents like jobTitleId, classificationId, deptId & classificationId was to be done and do some manipulations later using Set and Map. I was able to do that by simply overriding the equals and hashCode methods of Object class and was able to fetch the information (like in the following Map).
Map<LocationData, List<LocationData>>
The following is the class I used (its been shown to you so that it can be referred for my problem statement):
LocationData class
package com.astreait.bulkloader;
public class LocationData {
String locId, deptId, jobTitleId, classificationId;
#Override
public boolean equals(Object obj) {
LocationData ld = (LocationData)obj;
return this.deptId.equals(ld.deptId) && this.jobTitleId.equals(ld.jobTitleId) && this.classificationId.equals(ld.classificationId) &&
this.locId.equals(ld.locId);
}
#Override
public int hashCode() {
return deptId.hashCode() + jobTitleId.hashCode() + classificationId.hashCode() +locId.hashCode();
}
}
Problem:
I'm already known to which all fields of this object I need to make the comparison.
i.e I'm bound to use the variables named classificationId, deptId, jobTitleId & locId etc.
Need:
I need to customize this logic such that the fields Names (classificationId, deptId, jobTitleId & locId etc) can be pulled dynamically along with their values. So, as far as my understanding I made use of 2 classes (TableClass and ColWithData) such that the List of ColWithData is there in TableClass object.
I'm thinking what if I override the same two methods equals() & hashCode();
such that the same can be achieved.
TableClass class #1
class TableClass{
List<ColWithData> cwdList;
#Override
public boolean equals(Object obj) {
boolean returnVal = false;
// I need to have the logic to be defined such that
// all of the dynamic fields can be compared
return returnVal;
}
#Override
public int hashCode() {
int returnVal = 0;
// I need to have the logic to be defined such that
// all of the dynamic fields can be found for their individual hashCodes
return returnVal;
}
}
ColWithData class #2
class ColWithData{
String col; // here the jobTitleId, classificationId, deptId, locId or any other more fields info can come.
String data; // The corresponding data or value for each jobTitleId, classificationId, deptId, locId or any other more fields.
}
Please let me know if I'm proceeding in the right direction or I should make some any other approach. If it is ok to use the current approach then what should be performed in the equals and hashCode methods?
Finally I need to make the map as: (Its not the concern how I will make, but can be considered as my desired result from this logic)
Map<TableClass, List<TableClass>> finalMap;
EDIT I have been down voted. So, I made some modifications for my requirements again. (Please help me out solving this)
Using this class ColWithData is kind of ugly. You should be using a Map<String,String> :
package mypack;
import java.util.*;
public class TableClass {
/* HashMap containing your values:
map.put("locId", [data]);
...
*/
public Map<String,String> cwdMap;
public Map<String,String> getCwdMap() {
return cwdMap;
}
public void setCwdMap(Map<String,String> cwdMap) {
this.cwdMap = cwdMap;
}
#Override
public boolean equals(Object obj) {
TableClass tClass = (TableClass) obj;
for(String col: this.cwdMap.keyset()){
if (! tClass.cwdMap.get(col).equals(this.cwdMap.get(col)){
return false;
}
}
return true;
}
#Override
public int hashCode() {
int hCode = 0;
for(String col: this.cwdMap.keyset()){
hCode = hCode+cwdMap.get(col).hashCode();
}
return hCode;
}
}
In this code I never check for null values but your probably should.
There is another thing that confuse me in your code:
why use getter/setter if your property (cwdList) is public?
I think I have found the solution and its working for me.
Please let me know if there could be the simple or any other way out finding the solution for this problem.
The code snippet is:
package mypack;
import java.util.*;
public class TableClass {
public List<ColWithData> cwdList;
public List<ColWithData> getCwdList() {
return cwdList;
}
public void setCwdList(List<ColWithData> cwdList) {
this.cwdList = cwdList;
}
#Override
public boolean equals(Object obj) {
TableClass tClass = (TableClass) obj;
boolean returnVal = true;
for(ColWithData cwd: this.getCwdList()){
for(ColWithData innerCwd: tClass.getCwdList()){
if(cwd.getCol().equalsIgnoreCase(innerCwd.getCol())){
if(!cwd.getData().equalsIgnoreCase(innerCwd.getData()))
returnVal = false;
}
}
}
return returnVal;
}
#Override
public int hashCode() {
int hCode = 0;
for(ColWithData cwd: this.getCwdList()){
hCode = hCode+cwd.getData().hashCode();
}
return hCode;
}
}
And finally made a map as said:
Map<TableClass, List<TableClass>> map = new LinkedHashMap<TableClass, List<TableClass>>();
displaying the things as desired.
I am having this issue where I have a PiorityBlockingQueue to sort the items in it. The are several options the user can sort the items being added into the queue.
The one I'm stuck at is trying to order the queue by the most occurences of an Item.
The choice of the comparison is determined in the constructor of MyQueue. But the counts of (eg. Low, Medium, High) isnt determined until later. When it is determined, I wanted to call the update(String lst) method from ItemComparator to update the hashmap so that the sorting is correct.
So my issue is I can't call that method. I know I'm missing something but I can't figure it out. Any help? Maybe there a better design than what I doing now?
public class ItemComparator implements Comparator<Item>
{
public void update(String lst){
test = lst;
}
public int compare(Item o1, Item o2) {
HashMap<String,Integer> priority = new HashMap<>();
priority.put("LOW", 1);
priority.put("MEDIUM", 2);
priority.put("HIGH", 3);
if (priority.get(o1.getPriority()) > priority.get(o2.getPriority())) {
return -1;
}
if (priority.get(o1.getPriority()) < priority.get(o2.getPriority())) {
return 1;
}
return 0;
}
}
This statement wont work from this class comparator.update(aString);
public class MyQueue implements AQueue{
private Comparator<Ticket> comparator;
private PriorityBlockingQueue<Ticket> listOfTickets;
private String policy;
BlockingQImpl(String processingPolicy) throws InvalidDataException {
setPolicy(processingPolicy.toUpperCase());
setComparator(policy);
}
private void setComparator(String policy) throws InvalidDataException {
if (policy.equals("THIS")) {
comparator = new ItemComparator(countString);
}
listOfTickets = new PriorityBlockingQueue<>(10, comparator);
}
public void addList(int id) {
ticks.add(id)
comparator.update(aString);
}
}
I think your problem is the compilation error at comparator.update(aString); right?
It is because you have declared comparator as Comparator<Ticket>, that means, you are "seeing" it as a Comparator, and in a Comparator, there is no update() method.
You should declare it as ItemComparator
i.e.
private ItemComparator comparator;