/* This is wrapper class...
 Objective would be to push more functionality into this Class to enforce consistent definition
 */
public abstract class Collectable implements Comparable <Collectable> {
	public final String masterType = "Collectable";
	private String type;	// extender should define their data type

	// enumerated interface
	public interface KeyTypes {
		String name();
	}
	protected abstract KeyTypes getKey();  	// this method helps force usage of KeyTypes

	// getter
	public String getMasterType() {
		return masterType;
	}

	// getter
	public String getType() {
		return type;
	}

	// setter
	public void setType(String type) {
		this.type = type;
	}
	
	// this method is used to establish key order
	public abstract String toString();

	// this method is used to compare toString of objects
	public int compareTo(Collectable obj) {
		return this.toString().compareTo(obj.toString());
	}

	// static print method used by extended classes
	public static void print(Collectable[] objs) {
		// print 'Object' properties
		System.out.println(objs.getClass() + " " + objs.length);

		// print 'Collectable' properties
		if (objs.length > 0) {
			Collectable obj = objs[0];	// Look at properties of 1st element
			System.out.println(
					obj.getMasterType() + ": " + 
					obj.getType() +
					" listed by " +
					obj.getKey());
		}

		// print "Collectable: Objects'
		for(Object o : objs)	// observe that type is Opaque
			System.out.println(o);

		System.out.println();
	}
}
/*
 * Animal class extends Collectable and defines abstract methods
 */
public class Animal extends Collectable {
	// Class data
	public static KeyTypes key = KeyType.title;  // static initializer
	public static void setOrder(KeyTypes key) { Animal.key = key; }
	public enum KeyType implements KeyTypes {title, name, age, color}

	// Instance data
	private final String name;
	private final int age;
	private final String color;

	/* constructor
	 *
	 */
	public Animal(String name, int age, String color)
	{
		super.setType("Animal");
		this.name = name;
		this.age = age;
		this.color = color;
	}

	/* 'Collectable' requires getKey to help enforce KeyTypes usage */
	@Override
	protected KeyTypes getKey() { return Animal.key; }

	/* Getters / Accessors
	 * 
	 */
	public String getName() { return this.name; }
	public int getAge() { return this.age; }
	public String getColor() { return this.color; }

	
	/* 'Collectable' requires toString override
	 * toString provides data based off of Static Key setting
	 */
	@Override
	public String toString()
	{
		String output="";
		if (KeyType.name.equals(this.getKey())) {
			output += this.name;
		} else if (KeyType.age.equals(this.getKey())) {
			output += "00" + this.age;
			output = output.substring(output.length() - 2);
		} else if (KeyType.color.equals(this.getKey())) {
			output += this.color;
		} else {
			output += super.getType() + ": " + this.name + ", " + this.color + ", " + this.age;
		}
		return output;
		
	}

	// Test data initializer
	public static Animal[] animals() {
		return new Animal[]{
				new Animal("Lion", 8, "Gold"),
				new Animal("Pig", 3, "Pink"),
				new Animal("Robin", 7, "Red"),
				new Animal("Cat", 10, "Black"),
				new Animal("Kitty", 1, "Calico"),
				new Animal("Dog", 14, "Brown")
		};
	}
	
	/* main to test Animal class
	 * 
	 */
	public static void main(String[] args)
	{
		// Inheritance Hierarchy
		Animal[] objs = animals();

		// print with title
		Animal.setOrder(KeyType.title);
		Animal.print(objs);

		// convert to Coolection and sort in name order
		Animal.setOrder(KeyType.name);
		List<Animal> animals = new ArrayList<Animal>(Arrays.asList(objs));  // Array has asList conversion
		Collections.sort(animals);
		Animal.setOrder(KeyType.title);
		for (Animal animal : animals)
			System.out.println(animal);
	}

}
Animal.main(null);
class [LREPL.$JShell$13$Animal; 6
Collectable: Animal listed by title
Animal: Lion, Gold, 8
Animal: Pig, Pink, 3
Animal: Robin, Red, 7
Animal: Cat, Black, 10
Animal: Kitty, Calico, 1
Animal: Dog, Brown, 14

Animal: Cat, Black, 10
Animal: Dog, Brown, 14
Animal: Kitty, Calico, 1
Animal: Lion, Gold, 8
Animal: Pig, Pink, 3
Animal: Robin, Red, 7
public class Level extends Collectable {
    // Class data
	public static KeyTypes key = KeyType.title;  // static initializer
	public static void setOrder(KeyTypes key) { Level.key = key; }
	public enum KeyType implements KeyTypes {title, number, name, topic, difficulty, time, hint, hintContent}

	// Instance data
    private final int number;
    private final String name;
    private final String topic;
    private final String difficulty;
    private final int time;
    private final boolean hint;
    private final String hintContent;


    public Level(int number, String name, String topic, String difficulty, int time, boolean hint, String hintContent) {
        super.setType("Level");
        this.number = number;
        this.name = name;
        this.topic = topic;
        this.difficulty = difficulty;
        this.time = time;
        this.hint = hint;
        this.hintContent = hintContent;
    }

    @Override
    protected KeyTypes getKey() { return Level.key; }

    public int getNumber() { return this.number; }
    public String getName() { return this.name; }
    public String getTopic() { return this.topic; }
	public String getDifficulty() { return this.difficulty; }
	public int getTime() { return this.time; }
    public boolean getHint() { return this.hint; }
    public String getHintContent() { return this.hintContent; }

    @Override
    public String toString() {
        String output="";
        if (KeyType.number.equals(this.getKey())) {
            output += "00" + this.number;
            output = output.substring(output.length() - 2);
        }
        else if (KeyType.name.equals(this.getKey())) {
			output += this.name;
        }
        else if (KeyType.topic.equals(this.getKey())) {
			output += this.topic;
        }
        else if (KeyType.difficulty.equals(this.getKey())) {
			output += this.difficulty;
        }
        else if (KeyType.time.equals(this.getKey())) {
            output += "00" + this.time;
            output = output.substring(output.length() - 2);
        }
        else if (KeyType.hint.equals(this.getKey())) {
			output += this.hint;
        }
        else if (KeyType.hintContent.equals(this.getKey())) {
			output += this.hintContent;
        }
        else {
			output += super.getType() + ": " + this.number + ", " + this.topic + ", " + this.difficulty  + ", " + this.time  + ", " + this.hint  + ", " + this.hintContent;
		}
        return output;
        
    }

    public static Level[] levels() {
        return new Level[]{
                        new Level(1, "The Village","If Statements", "Easy", 30, true, "Try debugging"),
                        new Level(2,"The Jungle", "For Loops", "Medium", 60, false, "Take your time"),
                        new Level(3, "The Forest","De Morgan's Law", "Hard", 90, true, "Make a table for true and false"),
                        new Level(4, "The Park", "Traversing Arrays", "Easy", 30, false, "Hint here"),
                        new Level(5, "The Market", "While Loops", "Medium", 60, false, "Hint here"),
                        new Level(6, "The Neighborhood", "Recursive Loops", "Hard", 90, false, "hint here"),
        };
    }

    public static void main(String[] args){
        Level[] objs = levels();

        Level.setOrder(KeyType.title);
        Level.print(objs);

        Level.setOrder(KeyType.name);
        List<Level> levels = new ArrayList<Level>(Arrays.asList(objs));
        Collections.sort(levels);
        Level.setOrder(KeyType.name);
        for (Level level:levels)
            System.out.println(level);
        Level.print(objs);

        Level.setOrder(KeyType.difficulty);
        Level.print(objs);
    }
}


Level.main(null);
class [LREPL.$JShell$15B$Level; 6
Collectable: Level listed by title
Level: 1, If Statements, Easy, 30, true, Try debugging
Level: 2, For Loops, Medium, 60, false, Take your time
Level: 3, De Morgan's Law, Hard, 90, true, Make a table for true and false
Level: 4, Traversing Arrays, Easy, 30, false, Hint here
Level: 5, While Loops, Medium, 60, false, Hint here
Level: 6, Recursive Loops, Hard, 90, false, hint here

The Forest
The Jungle
The Market
The Neighborhood
The Park
The Village
class [LREPL.$JShell$15B$Level; 6
Collectable: Level listed by name
The Village
The Jungle
The Forest
The Park
The Market
The Neighborhood

class [LREPL.$JShell$15B$Level; 6
Collectable: Level listed by difficulty
Easy
Medium
Hard
Easy
Medium
Hard

import java.util.HashMap;

public class Stages {
    // create a new HashMap
    HashMap<String, Level> names = new HashMap<>();

    /* Add Pets
     * 
     */
    public Stages() {
        // add some key-value pairs to the HashMap
        names.put("The Beginning", new Level(1, "The Village","If Statements", "Easy", 30, true, "Try debugging"));
        names.put("Monkeying Around", new Level(2,"The Jungle", "For Loops", "Medium", 60, false, "Take your time"));
        names.put("The Middle", new Level(3, "The Forest","De Morgan's Law", "Hard", 90, true, "Make a table for true and false"));
        names.put("Monkey See Monkey Do", new Level(4, "The Park", "Traversing Arrays", "Easy", 30, false, "Hint here"));
        names.put("Monkeys Jumping on The Best", new Level(5, "The Market", "While Loops", "Medium", 60, false, "Hint here"));
        names.put("The End", new Level(6, "The Neighborhood", "Recursive Loops", "Hard", 90, false, "hint here"));
    } 

    /* Remove Pet
     * 
     */
    public Level remove(String key) {
        // check if a key exists in the HashMap then remove
        Level level = null;
        if (names.containsKey(key)) {
            level = names.get(key);
            names.remove(key);
        }
        return level;
    }

    /* Print Pets
     * 
     */
    public void print() {
        // iterate over the keys in the HashMap
        for (String name: names.keySet()) {
            Level obj = names.get(name);
            System.out.println("The " + obj.getNumber() + " level is called " + name + " and covers " + obj.getTopic() + " amd will have " + obj.getTime() + ".");
        }
        System.out.println();
    }

    /* Tester Method
     * 
     */
    public static void main(String[] args) {

        // intialize Pets
        Stages stages = new Stages();
        stages.print();
        
        // remove a Pet
        String key = "The Middle";
        Level level = stages.remove(key);
        if (level == null) {
            System.out.println(key + " not found");
        } else {
            System.out.println("Removed: " + key + ", " + level);
        }
        stages.print();

    }
}
Stages.main(null);
The 2 level is called Monkeying Around and covers For Loops amd will have 60.
The 1 level is called The Beginning and covers If Statements amd will have 30.
The 3 level is called The Middle and covers De Morgan's Law amd will have 90.
The 4 level is called Monkey See Monkey Do and covers Traversing Arrays amd will have 30.
The 5 level is called Monkeys Jumping on The Best and covers While Loops amd will have 60.
The 6 level is called The End and covers Recursive Loops amd will have 90.

Removed: The Middle, Hard
The 2 level is called Monkeying Around and covers For Loops amd will have 60.
The 1 level is called The Beginning and covers If Statements amd will have 30.
The 4 level is called Monkey See Monkey Do and covers Traversing Arrays amd will have 30.
The 5 level is called Monkeys Jumping on The Best and covers While Loops amd will have 60.
The 6 level is called The End and covers Recursive Loops amd will have 90.

import java.util.HashSet;
import java.util.Set;

public class LevelSet {
    public static void main(String[] args) {
        // create a new HashSet
        Set<String> levels = new HashSet<>();

        // add some elements to the Set
        levels.add("The House");
        levels.add("The Street");
        levels.add("The Sewers");

        // print out the Set
        System.out.println(levels);

        // check if an element is in the Set
        boolean hasHouse = levels.contains("TheHouse");
        System.out.println("Has house: " + hasHouse);

        // remove an element from the Set
        levels.remove("The House");
        System.out.println("Removed house");

        // print out the Set
        System.out.println(levels);

        // add duplicate
        System.out.println("add duplicate location");
        levels.add("The House");  // no action
        System.out.println(levels);
        // add duplicate
        System.out.println("add the Water Park");
        levels.add("The Water Park");
        System.out.println(levels);

        // using forEach() method with a lambda expression
        levels.forEach(level -> {
            String message = "I ";
            // ternary operation for like, don't like
            message += level.equals("The House") ? "like" : "don't like";
            // complete sentance
            message += " " + level  + "for a level name";
            System.out.println(message);
        });

    }
}
LevelSet.main(null);
[The House, The Street, The Sewers]
Has house: false
Removed house
[The Street, The Sewers]
add duplicate location
[The House, The Street, The Sewers]
add the Water Park
[The House, The Street, The Sewers, The Water Park]
I like The Housefor a level name
I don't like The Streetfor a level name
I don't like The Sewersfor a level name
I don't like The Water Parkfor a level name
import java.util.HashMap;

public class Pets {
    // create a new HashMap
    HashMap<String, Animal> names = new HashMap<>();

    /* Add Pets
     * 
     */
    public Pets() {
        // add some key-value pairs to the HashMap
        names.put("Leo", new Animal("Lion", 8, "Gold"));
        names.put("Porky", new Animal("Pig", 3, "Pink"));
        names.put("Ro-Ro", new Animal("Robin", 7, "Red"));
        names.put("Midnight", new Animal("Cat", 10, "Black"));
        names.put("Hobbes", new Animal("Kitty", 1, "Calico"));
        names.put("Duke", new Animal("Dog", 14, "Brown"));
    } 

    /* Remove Pet
     * 
     */
    public Animal remove(String key) {
        // check if a key exists in the HashMap then remove
        Animal animal = null;
        if (names.containsKey(key)) {
            animal = names.get(key);
            names.remove(key);
        }
        return animal;
    }

    /* Print Pets
     * 
     */
    public void print() {
        // iterate over the keys in the HashMap
        for (String name: names.keySet()) {
            Animal obj = names.get(name);
            System.out.println(name + " is a " + obj.getColor() + " " + obj.getName() + " and is " + obj.getAge() + " years old.");
        }
        System.out.println();
    }

    /* Tester Method
     * 
     */
    public static void main(String[] args) {

        // intialize Pets
        Pets pets = new Pets();
        pets.print();
        
        // remove a Pet
        String key = "Hobbes";
        Animal animal = pets.remove(key);
        if (animal == null) {
            System.out.println(key + " not found");
        } else {
            System.out.println("Removed: " + key + ", " + animal);
        }
        pets.print();

    }
}
Pets.main(null);
Hobbes is a Calico Kitty and is 1 years old.
Leo is a Gold Lion and is 8 years old.
Porky is a Pink Pig and is 3 years old.
Ro-Ro is a Red Robin and is 7 years old.
Duke is a Brown Dog and is 14 years old.
Midnight is a Black Cat and is 10 years old.

Removed: Hobbes, Animal: Kitty, Calico, 1
Leo is a Gold Lion and is 8 years old.
Porky is a Pink Pig and is 3 years old.
Ro-Ro is a Red Robin and is 7 years old.
Duke is a Brown Dog and is 14 years old.
Midnight is a Black Cat and is 10 years old.

import java.util.HashSet;
import java.util.Set;

public class AnimalSet {
    public static void main(String[] args) {
        // create a new HashSet
        Set<String> animals = new HashSet<>();

        // add some elements to the Set
        animals.add("lion");
        animals.add("dog");
        animals.add("cat");

        // print out the Set
        System.out.println(animals);

        // check if an element is in the Set
        boolean hasLion = animals.contains("lion");
        System.out.println("Has lion: " + hasLion);

        // remove an element from the Set
        animals.remove("lion");
        System.out.println("Removed lion");

        // print out the Set
        System.out.println(animals);

        // add duplicate
        System.out.println("add duplicate dog");
        animals.add("dog");  // no action
        System.out.println(animals);
        // add duplicate
        System.out.println("add pig");
        animals.add("pig");
        System.out.println(animals);

        // using forEach() method with a lambda expression
        animals.forEach(animal -> {
            String message = "I ";
            // ternary operation for like, don't like
            message += animal.equals("dog") ? "like" : "don't like";
            // complete sentance
            message += " " + animal + "s " + "for pets";
            System.out.println(message);
        });

    }
}
AnimalSet.main(null);
[cat, dog, lion]
Has lion: true
Removed lion
[cat, dog]
add duplicate dog
[cat, dog]
add pig
[cat, dog, pig]
I don't like cats for pets
I like dogs for pets
I don't like pigs for pets