-1

I have a program where a user can create a task and set it as a favorite or not. Once that has finished, the user should be able to find it again when entering the name. The problem is, my get method is returning null when used.

I have tried storing it first within a MapEntry, element, but it only leads to a NullPointerException. I have also tried just displaying the hashmap getting the key itself but it only leads to the result being null. My MapEntry class consists of private variables to get the key and value of my Favorites class:

Favorites key;
boolean value;
MapEntries next;

with its constructor being:

public Favorites(String task, boolean bookmark) {
    this.task = task;
    this.bookmark = bookmark;
}

The Favorites class also has the methods:

@Override
public int hashCode(){
    return (bookmark ? 0 :1);
}

@Override
public boolean equals(Object object){
    Favorites temp = (Favorites) object;
    return this.task.equals(temp);
}

alongside its setters and getters.

and here is the MapEntries class:

public class MapEntries{
Favorites key;
boolean value;
MapEntries entry;

public MapEntries(Favorites key, boolean value) {
    this.key = key;
    this.value = value;
}

public Favorites getKey() {
    return key;
}

public void setKey(Favorites key) {
    this.key = key;
}

public boolean isValue() {
    return value;
}

public void setValue(boolean value) {
    this.value = value;
}

public MapEntries getEntry() {
    return entry;
}

public void setEntry(MapEntries entry) {
    this.entry = entry;
}

}

Within my custom HashMaps class I have my get method to call in my main program:

First creating the variables at the start of the class:

public class HashMaps{
 private static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; //16
 private MapEntries[] holder = new MapEntries[DEFAULT_INITIAL_CAPACITY];

 public MapEntries get(Favorites key) {
    if (key == null){
        System.out.println("No results...");
        return null;
    }
    int value = key.hashCode();
    int holderNumber = getSupplementalHash(value);
    if (holder[holderNumber] == null){
        System.out.println("No results...");
        return null;
    }
    else{
        MapEntries existingElement = holder[holderNumber];

        while (existingElement != null) {
            System.out.println("Traversing maps for key " + existingElement.getKey());
            if (existingElement.key.equals(key)) {
                return existingElement;
            }
            existingElement = existingElement.entry;
        }
    }
    return null;
}

//the get Supplemental Hash method:

 private int getSupplementalHash(int h) {
 h ^= (h >>> 20) ^ (h >>> 12);
 return h ^ (h >>> 7) ^ (h >>> 4);
 }
}

my method to create a task:

first defining a static hashmap outside of my public static void main method:

static HashMaps hashMaps = new HashMaps();

public static void forFavorites(){

    int numberOfTasks = 0;
    System.out.println("Enter the number of tasks you want to add: ");
    numberOfTasks = Integer.parseInt(key.nextLine());
    for (int taskNumber = 1; taskNumber<=numberOfTasks; taskNumber++) {
        System.out.println("Task no. " + taskNumber);
        System.out.println("\t Enter the new task's title: ");
        String newTask = key.nextLine();
        String trimSpaces = newTask.trim();
        if (trimSpaces.isEmpty() || newTask.length() == 0){
        System.out.println("\n Invalid. Title cannot be blank");
         }
         else {
            Favorites toFavorite = new Favorites(trimSpaces, false);
            System.out.println("Adding " + toFavorite.getTask());
            hashMaps.put(toFavorite, false);
            System.out.println("Do you want to favorite this task? Y/N");
            String choice = key.nextLine();
            if (choice.equalsIgnoreCase("Y")){
                System.out.println();
                System.out.println();
                System.out.println("User chose to add "+ 
 toFavorite.getTask() + " as a favorite");
                Favorites favorited = new Favorites(trimSpaces, true);
                hashMaps.put(favorited,true);
                System.out.println("Press enter to continue..");
                key.nextLine();

            } else {
                System.out.println("Press enter to continue..");
                key.nextLine();

            }

        }
        }
    System.out.println(hashMaps.toString() + " ");
    homeMenu();
}

and finally my search method

 public static void search(){
    System.out.println("Enter the task you want to find: ");
    String lookFor = key.nextLine();
    Favorites search = new Favorites(lookFor, false);
    System.out.println("\nNumber of tasks found: "+ hashMaps.getSize());
    System.out.println(hashMaps.get(search));
    System.out.println();
    homeMenu();
} 

As of now the result is:

Enter the task you want to find: 
Task

Number of tasks found: 1
Traversing maps for key Task: false
null
Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • Where is `hashMaps` defined? Is this some sort of linkedList? – Scary Wombat Oct 29 '19 at 01:23
  • 1
    [Please add a minimal, complete, and verifiable example](https://stackoverflow.com/help/mcve) – Scary Wombat Oct 29 '19 at 01:26
  • hashMaps is defined outside the main program as: `HashMaps hashMaps = new HashMaps();` – Joey Deguzman Oct 29 '19 at 01:26
  • @ScaryWombat I'll work on it now – Joey Deguzman Oct 29 '19 at 01:27
  • 2
    You're not showing key code still -- where do you define the equals and hashCode method in Favortes, for example. Please post a valid [mre] as per @ScaryWombat's comment above. – Hovercraft Full Of Eels Oct 29 '19 at 01:27
  • 2
    Possibly related: [Understanding the workings of equals and hashCode in a HashMap](https://stackoverflow.com/q/1894377), [What issues should be considered when overriding equals and hashCode in Java?](https://stackoverflow.com/q/27581) – Pshemo Oct 29 '19 at 01:33
  • 2
    I am still unsure whether this is some custom class or he is meaning `HashMap` – Scary Wombat Oct 29 '19 at 01:38
  • I agree. Without a decent [mre] we are forced to resort to guessing. Not good – Hovercraft Full Of Eels Oct 29 '19 at 01:39
  • Also, to the OP, what does this mean: "The hashCode method is created within my Favorites class and has this since I am using a boolean for its value:"? You still don't show the Favorites class's hashCode or equals methods, and your comment doesn't really make much sense. – Hovercraft Full Of Eels Oct 29 '19 at 01:45
  • 3
    I’m pretty certain you have not (properly) implemented `equals()` and `hashCode()` methods in your `Favorites` class. Please follow the links posted by Pshemo above to read about how to do this properly. – Bohemian Oct 29 '19 at 01:46
  • It took a while to edit everything but i hope this is better – Joey Deguzman Oct 29 '19 at 01:50
  • 2
    `return this.task.equals(temp);` is wrong as will always be false – Scary Wombat Oct 29 '19 at 01:52
  • I have changed the line to `return this.task.equals(temp.task);` but it now returns the hash code instead of null – Joey Deguzman Oct 29 '19 at 01:58
  • By `HashMap` in question title you are referring to standard one provided via `java.util.HashMap` or to your own `HashMap**s**` class? – Pshemo Oct 29 '19 at 02:04
  • it is my own implementation of the class HashMap – Joey Deguzman Oct 29 '19 at 02:07
  • Are you solving some kind of homework which forces you to use of your own map, or can you use already existing one like `java.util.HashMap`? – Pshemo Oct 29 '19 at 02:08
  • It is a project given to us to have us create a HashMap ourselves without using any available packages – Joey Deguzman Oct 29 '19 at 02:10
  • I was afraid of that... Anyway there are few things which doesn't feel right (although I am not sure if that is also some kind of requirement or not). For instance map.get(key) method shouldn't be returning *entry* (as key-value pair) but *value* held under specified *key*. Also I am not sure why you have Favorites class at all, it feels more natural to have mapping like `Map favorites` or `Map favorites` instead. – Pshemo Oct 29 '19 at 02:30

1 Answers1

3

Let's just go with - you are doing this to grasp an understanding of the depths of java - otherwise you should just use HashMap.

A key to a hashmap should be just that - the key. In your case it is the name of the task. You can make your own class (Favorites) if you want but its only variable should be "name". And I would name that class something like TaskKey instead of Favorites. Use a constructor with the name as the parameter.

Hashcode must always be matched up with equals. This means that if equals compares the name then hashCode must hash the name.

public int hashCode() {
    return name.hashCode();
}

You can write your own hashcode but be careful. It has a dramatic effect on sorting and indexing in hashmaps. I suggest you don't.

Now you are left with the boolean called favorite. This is definitely not part of the key, it is the data associated with the key. Maybe make a new class called "Task", create an instance of it (new), and have it as the value. Maybe even a constructor that forces the key to be part of Task.

public class Task {
    private TaskKey taskKey;
    private boolean favorite;

    public Task(TaskKey key) {
        taskKey = taskKey;
    }
}

TaskKey taskKey = new TaskKey(name);
Task myTask = new Task(taskKey);
myTask.favorite = someBooleanAnswer;

After asking the user the questions and creating the TaskKey and the Task then you would "put" them in the HashMap(s).

hashMaps.put(task.taskKey, task);

And later you can find the task with the "get" method.

Task task = hashMaps.get(task.taskKey);

Further reading to get an idea of the complexity of a HashMap. I would also use getters / setters but I left them out for brevity.

fedup
  • 1,209
  • 11
  • 26