A list as an instance variable
A class can keep a list in an instance variable, just as it keeps a String or an int. Here a recipe has a name and a list of ingredients:
public class Main {
public static void main(String[] args) {
Recipe pancakes = new Recipe("Pancakes");
pancakes.addIngredient("flour");
pancakes.addIngredient("milk");
pancakes.addIngredient("eggs");
Recipe toast = new Recipe("Toast");
toast.addIngredient("bread");
toast.addIngredient("butter");
System.out.println(pancakes.getName() + " needs " + pancakes.ingredientCount() + " ingredients");
System.out.println(toast.getName() + " needs " + toast.ingredientCount() + " ingredients");
}
}import java.util.ArrayList;
public class Recipe {
private String name;
private ArrayList<String> ingredients;
public Recipe(String name) {
this.name = name;
this.ingredients = new ArrayList<>();
}
public void addIngredient(String ingredient) {
this.ingredients.add(ingredient);
}
public int ingredientCount() {
return this.ingredients.size();
}
public String getName() {
return this.name;
}
}Pancakes needs 3 ingredients
Toast needs 2 ingredientsimport java.util.ArrayList;is at the top ofRecipe.java, because Recipe uses ArrayList. Each file imports what it uses.Main.javaneeds no import here:mainnever writesArrayList.private ArrayList<String> ingredients;declares the instance variable. Like the others, it's private, so code outside Recipe can't reach the list.- The constructor makes the list:
this.ingredients = new ArrayList<>();. The constructor runs once for each new Recipe, so each recipe gets a new, empty list of its own. The pancakes' three ingredients never mix with the toast's two. - The methods use the list through
this.ingredients, like any other instance variable.addIngredientpasses the ingredient on to the list'sadd, andingredientCountreturns the list'ssize().
main never touches the list itself: it asks the recipe. So the recipe's methods decide what can be done with its ingredients. This Recipe can add and count them, and nothing else. There's no way to remove an ingredient, because Recipe has no method for that.
Forgetting to make the list
Declaring the instance variable doesn't make a list. private ArrayList<String> ingredients; only says what the variable can refer to, and an instance variable of a class type is null until something gives it an object (module 22). If the constructor leaves out new ArrayList<>(), the first add crashes:
public class Main {
public static void main(String[] args) {
Recipe salad = new Recipe("Salad");
salad.addIngredient("lettuce");
System.out.println(salad.ingredientCount());
}
}import java.util.ArrayList;
public class Recipe {
private String name;
private ArrayList<String> ingredients;
public Recipe(String name) {
this.name = name;
}
public void addIngredient(String ingredient) {
this.ingredients.add(ingredient);
}
public int ingredientCount() {
return this.ingredients.size();
}
}Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.util.ArrayList.add(Object)" because "this.ingredients" is null
at Recipe.addIngredient(Recipe.java:12)
at Main.main(Main.java:4)The message names the instance variable that was null, this.ingredients. The first at line says where it happened: in addIngredient, line 12 of Recipe.java. The line below says who called it: main, on line 4. The fix is in neither place, though. It's the missing line in the constructor, where the recipe should have gotten its list.