2

I've tried looking at posts on this issue but am still having some trouble with this error in my code. So in the fourth line, I create an instance variable called SongDatabase to access the SongDatabase class. But when I get down to the line, SongDatabase.addNewSong(); under case 1, I get a java.lang.NullPointerException: null error.

Interface class:

public class Interface 
{
    Scanner console = new Scanner(System.in);
    private SongDatabase SongDatabase;

    public static void main(String[] args) {
        Interface intFace = new Interface();
        intFace.run();
    }

    private void run() {
        switch (userInput) {
        case 1: 
            SongDatabase.addNewSong();
            break;
        case 2:
            SongDatabase.removeSong();
            break;
        case 3:
            SongDatabase.sortSongs();
            break;
        default:
            System.out.println("Please enter a valid number.");
            break;

    }
}

SongDatabase class:

public class SongDatabase {
    Scanner console = new Scanner(System.in);  
    private Song song1, song2, song3, song4;

public void addNewSong() {        
        if (song1 == null) {
            song1 = getFromUser();
        }
        else if (song2 == null) {
            song2 = getFromUser();
        }    
        else if (song3 == null) {
            song3 = getFromUser();
        }
        else if (song4 == null) {
            song4 = getFromUser();
        }
        else {
        System.out.println("The database is currently full. Please delete a song before adding a new one.");
       }    
    }

I've stepped through the debugger and I know that the instance variable, SongDatabase = null, which is probably causing the error? I previously had a line

SongDatabase SongDatabase = new SongDatabase();
SongDatabase.addNewSong();

instead, but I realised this was creating a new SongDatabase object everytime and wiping what I had stored in there so I had to change it. I'd really appreciate a solution because I have no clue, thanks!

Lachie
  • 105
  • 1
  • 11
  • Constructors are basically used to initialize class fields. So hopefully you won't miss this part in future, that you can actually initialize variables inside the constructor, by creating one. – nIcE cOw May 04 '15 at 01:16
  • 1
    you shouldn't name the class "Interface" that's just confusing, for those that use interfaces – Alexander Mills May 04 '15 at 01:27

4 Answers4

6

You shouldn't give your instance field the same name as the class because that causes Variable shadowing - Wikipedia says (in part) variable shadowing occurs when a variable declared within a certain scope (decision block, method, or inner class) has the same name as a variable declared in an outer scope. At the level of identifiers (names, rather than variables), this is known as name masking. And you could define the reference at declaration like

private SongDatabase songDatabase = new SongDatabase();

Then something like

private void run() {
    switch (userInput) {
    case 1: 
        songDatabase.addNewSong();
        break;
    case 2:
        songDatabase.removeSong();
        break;
    case 3:
        songDatabase.sortSongs();
        break;
    default:
        System.out.println("Please enter a valid number.");
        break;
    }
}
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
  • "You shouldn't ..."? You shouldn't give advice like that without at least attempting to explain why :-) There's a difference between rules and conventions. – paxdiablo May 04 '15 at 01:03
  • 1
    I'm struggling to find an actual case where shadowing a class with a variable would have adverse effects. It appears to still work okay though maybe there's some edge cases I haven't considered. I would have just said it's better to avoid confusion :-) But it's still good advice anyway. May want to refer to https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html as a source of information. – paxdiablo May 04 '15 at 01:12
2

It is null because it is never being instantiated. Create SongDatabase in your main method to get around your original problem:

public static void main(String[] args) {
    Interface intFace = new Interface();
    SongDatabase = new SongDatabase();
    SongDatabase.addNewSong();
    intFace.run();
}
garryp
  • 5,508
  • 1
  • 29
  • 41
2

To avoid confusion name your variables starting with a lower case letter.

 private SongDatabase songDatabase;

This way it is clear that when you write songDatabase you mean the instance and when you write SongDatabase you are referring to the class.

You need to instantiate the instance of the class before you can use it. It seems that you are already aware of this from the question but it is just a matter of where to do it. For a quick fix you can instantiate it at the point where you declare the variable. Later you can look into a better design. Therefore:

 private SongDatabase songDatabase = new SongDatabase();
Vincent Ramdhanie
  • 102,349
  • 23
  • 137
  • 192
1

You were getting the NullPointerException as the class variable for SongDatabase have never been instantiated. To initialize the class variables we can use constructor, please see the code details below. Also to avoid the naming confusion we can use this keyword to have better code readability.

import java.util.Scanner;

public class Interface
{
    private Scanner console;
    private SongDatabase songDatabase;

    public Interface()
    {
        this.songDatabase = new SongDatabase(); // Initialize the SongDatabase class and .
        this.console = new Scanner(System.in); // Initialize the console reference with scanner class.
    }

    public static void main(String[] args)
    {
        Interface intFace = new Interface();
        intFace.run();
    }

    private void run()
    {
        System.out.println("1. Add Song");
        System.out.println("2. Remove Song");
        System.out.println("3. Sort Song");
        System.out.print("Please Enter Choice: ");

        int userInput = console.nextInt(); // Get the data from user input

        switch (userInput)
        {
            case 1:
                this.songDatabase.addNewSong();
                break;

            case 2:
                this.songDatabase.removeSong();
                break;

            case 3:
                this.songDatabase.sortSongs();
                break;

            default:
                System.out.println("Please enter a valid number.");
                break;
        }
    }
}