0

I have an ArrayList called "filmList" in a separate class called actors, I want to use case 2 in the switch to call newActor.filmList.get(i); but I keep getting object may not be initialized errors from the compiler. If I put the same line in switch case 1 it works fine, but in case 2 i get the error. Can someone please tell me how I can call a method on the object from outside where the constructor creates the newActor object, I will be eternally grateful, it is doing my head in and my lecturer is terrible at explaining things. Thanks.

public class ActorsMain {

public static void main(String[] args) {

    Scanner kb = new Scanner(System.in);

    String fName="";
    String lName="";
    String address="";
    int age;
    String filmEntry="";
    String code="";


    ArrayList actors = new ArrayList(); 
    ArrayList films = new ArrayList();
    int choice=0;
    while(choice!=3){
    System.out.println("Make your selection.\n1. Add Actor\n2. List Actors");
    choice=kb.nextInt();

    switch (choice){

    case 1:
            System.out.println("\nPlease enter the actors first name:");
            fName=kb.next();
            System.out.println("Please enter the actors second name:");
            lName=kb.next();
            System.out.println("Please enter the actors address:");
            address=kb.next();
            System.out.println("Please enter the actors age:");
            age=kb.nextInt();
            kb.nextLine();

            for(int a=0;a<10;a++){
            System.out.println("Please enter the actors film.\nType 'Stop' to stop entering films.");
            filmEntry=kb.nextLine();
            //kb.nextLine();
                if(filmEntry.equalsIgnoreCase("stop")){
                    break;
                }
                else {

                    Films filmObject = new Films(filmEntry,code);
                    films.add(filmObject);
                }
            }


            Actors newActor = new Actors(fName,lName,address,age);
            actors.add(newActor);

            newActor.setFilm(films);
            films.clear();
            break;

    case 2:

        break; 


    }
    }





}       

}

Nodstuff
  • 3
  • 1
  • 3

3 Answers3

0

Im guessing your Actor class has an ArrayList called filmList and you want to get the value from it at a certain position. If that is the case you should probably create a getFilmListIndex(int pos) method in your Actor class that takes in an index value and returns whatever object your film list stores. Assuming your filmList stores String it might look something like this.

  public String getFilmListIndex(int pos)
      {
         return filmList.get(i);
      }

Then call this method from your ActorMain class.

  String result = newActor.getFilmListIndex(i);
sirFunkenstine
  • 8,135
  • 6
  • 40
  • 57
  • Thanks for your answer, but my problem is that when I type "newActor.getFilmListIndex" (or whatever method I try to call) newActor is underlined in red and it says the local variable may not be initialized. If I move the exact same line up before the break; in case 1 it works fine. – Nodstuff Oct 22 '13 at 00:40
0

age is uninitialized when you declare it. In case 1 it will be set, but in case 2 it is not clear that it has been set yet.

You could assign it a dummy value when you declare it, but in general it is better practice to mostly scope variables only where they are actually being used & have a valid value.

That would suggest putting all the actor details into a separate method or (not as nice) inside {} curly brackets, and only declare them as you are assigning the value. Having accessible variables hanging around with undefined, dummy or outdated values is provably less correct than only having a variable declared with a scope equivalent to when it's value is valid & applicable.

Thomas W
  • 13,940
  • 4
  • 58
  • 76
  • yes but age is only used in case 1. case 1 is to add an actor, get all the details and create an actor object called "newActor" and store it in an arraylist in actorMain and creates a film object with a film title and stores it in an arraylist in the actor class. case 2 only prints the stored actor information from the arraylist in actorMain and the film information from the arraylist in the actor class. I can print the actors fine, but when i try to print the film information in a loop by using "newActor.filmList.get(i)" it says newActor isn't initialized. sorry for the wall of text. – Nodstuff Oct 22 '13 at 00:45
0

You will have to declare newActor outside the scope of the switch statement. Inside case 2 of your switch, newActor doesn't exist.

int c = 0;
switch (c) {
    case 1:
        Object obj = new Object();
        break;
    case 2:
        System.out.println(obj.toString()); // obj only exists in case 1
        break;
}

This is actually a little peculiar and maybe somebody else can explain why, but the error you are getting seems to be particular to the switch statement. If you try to do the following:

int c = 0;
if (c == 1) {
    Object obj = new Object();
} else if (c == 2) {
    System.out.println(obj.toString());
}

You will get a different error that says "cannot find symbol" which is more to the point. Apparently cases inside a switch share scope such that they can "see each other". I assume this is related to the sans-break fall-through. Switches are all one block and the cases only determine the entrance point.

I'm not sure what you are trying to do to tell you where to put your newActor declaration but the point is right now case 2 in your switch can't use it. It only exists inside case 1.

Also you shouldn't use a switch for such a long statement. You should at least refactor it so it uses if statements. Switches are just not meant for this kind of thing. They are meant for long conditions with lots of possibilities and small statements for each case:

char operator = '*';
int leftNumber = 5;
int rightNumber = 9;

switch (operator) {
    case '+': System.out.println(leftNumber + rightNumber);
              break;
    case '-': System.out.println(leftNumber - rightNumber);
              break;
    case '*': System.out.println(leftNumber * rightNumber);
              break;
    case '/': System.out.println(leftNumber / rightNumber);
              break;
    case '^': System.out.println(Math.pow(leftNumber, rightNumber));
              break;
    default:  System.out.println("Unknown operator");
}

As a long side note, you are not passing a type parameter to your ArrayLists. Java doesn't know that your ArrayLists contain Actors and Films unless you say so:

ArrayList<Actors> actors = new ArrayList<Actors>();

ArrayLists and other generics are supposed to be initialized with a bracketed parameter of <E> where E is the desired class type of the elements in the array.

The type parameter is a little bit like extending a class. The ArrayList class will have E all over the source code and when you pass Actor in to the E parameter, E is replaced with Actor.

class ArrayList<E> {
    Object[] array = new Object[some_length];
    public E get(int index) {
        return (E)array[index];
    }
}

becomes

class ArrayList<Actor> {
    Object[] array = new Object[some_length];
    public Actor get(int index) {
        return (Actor)array[index];
    }
}

Note that even then whether or not Java knows that that ArrayList contains Actors while the application is running is still vague due to the way generics are implemented. They are implemented using something called erasure. At runtime there is no way to know that the ArrayList is of the Actor type.

If you declare them with the type parameter, you will be able to access their elements using get() as Actors and Films in your code which you won't be able to right now.

In other words you can do this:

System.out.println(actors.get(aIndex).filmList.get(fIndex));

Which it looks like you are starting to try to do under case 2 but you also won't be able to do at the moment. Without <Actor> or <Film> it will tell you "cannot find symbol" or "incompatible types" because the ArrayList holds an array of Object without the type parameter. (It's still an array of Object with the type parameter but you can use it like the type you pass in.)

Radiodef
  • 37,180
  • 14
  • 90
  • 125
  • Thank you so much, this helps a lot. I will try to restructure using if-else statements and also the type parameter to the arraylist and see how I get on. Thanks again, I will share this answer with some of the guys in my course because I've learned more from this answer than I have from my lecturer in 6 weeks. (I can't upvote but if I could I would) – Nodstuff Oct 22 '13 at 01:28
  • You're welcome. If you want to read more about generics there is a Java tutorial for it: http://docs.oracle.com/javase/tutorial/java/generics/index.html But generics are very complicated and you don't need to know anything more than what I said to use something like ArrayList correctly. The tutorial is probably way TMI. I can't find an official doc for local variable scope specifically but there are some around Google and on SO. Generally a rule is that any time you put something in a curly brace block, only those inside the block and any inner blocks can see it. – Radiodef Oct 22 '13 at 01:45
  • Thanks to you I have it pretty much sorted, I can finally go to bed! I can't thank you enough. I added the and type params and used the System.out you supplied and with a bit of tinkering it's working enough for me to sleep and polish off tomorrow. You sir, are a gentleman and a scholar! – Nodstuff Oct 22 '13 at 01:51