Collectibles

Introduction

In Computer Science, collections refer to groups of related data items stored in a structure that allows efficient access, organization, and manipulation. Collections are fundamental to software development and are used in everything from games and databases to search engines and machine learning.

Learning Objectives

  • Understand how to represent data using Java classes
  • Apply ArrayLists, HashMaps, and loops to manage collections
  • Practice object-oriented programming: constructors, encapsulation, and methods
  • Build a basic text-based inventory system for collectibles

What is a Collection?

A collection is a data structure that holds multiple elements, typically of the same type. Collections provide standard methods to add, remove, search, and iterate over elements.

Common collection types:

  • List (Array) – ordered collection of elements
  • Set – unordered collection of unique elements
  • Dictionary (Map, HashMap) – key-value pairs for fast lookup
  • Stack & Queue – collections with specific access patterns (LIFO, FIFO)

Why Use Collections?

Collections are used to:

  • Organize data logically (e.g., storing user profiles, game objects, or search history)
  • Perform batch operations (e.g., filtering, sorting, or searching)
  • Reuse common algorithms with different data types

Collection Types and Their Use Cases

  1. List (ArrayList) • Maintains order. • Allows duplicates. • Great for sequences, history logs, or indexed data.

import java.util.ArrayList; import java.util.List;

List fruits = new ArrayList<>(); fruits.add("apple"); fruits.add("banana"); fruits.add("cherry"); fruits.add("date");

  1. Set (HashSet) • Unordered and contains only unique items. • Useful for checking membership and removing duplicates.

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

Set uniqueTags = new HashSet<>(); uniqueTags.add("AI"); uniqueTags.add("Python"); uniqueTags.add("Data"); uniqueTags.add("Python"); // No effect, already present

  1. Dictionary (HashMap) • Maps keys to values. • Fast retrieval by key. • Useful for objects, configurations, or lookup tables.

import java.util.HashMap; import java.util.Map;

Map<String, Object> userProfile = new HashMap<>(); userProfile.put(“name”, “Alice”); userProfile.put(“score”, 1200); userProfile.put(“level”, 5);

  1. Stack • LIFO: Last In, First Out. • Used in undo systems, expression parsing, function calls.

import java.util.Stack;

Stack stack = new Stack<>(); stack.push("action1"); String lastAction = stack.pop();

  1. Queue • FIFO: First In, First Out. • Used in task scheduling, print queues, or event handling.

import java.util.LinkedList; import java.util.Queue;

Queue queue = new LinkedList<>(); queue.add("task1"); queue.add("task2"); queue.add("task3"); queue.poll(); // Removes "task1"

Part 1: Define a Collectible Class

// This class represents a collectible item, like a card, toy, or in-game item
public class Collectible {

    // Fields (also called instance variables) that store information about each collectible
    private String name;   // The name of the collectible (e.g., "Dragon Blade")
    private String type;   // The category or type (e.g., "Weapon", "Fire", "Water")
    private int rarity;    // An integer representing rarity level (1 = Common, 5 = Legendary)

    // Constructor: This method is called when a new Collectible object is created.
    // It sets the initial values for name, type, and rarity.
    public Collectible(String name, String type, int rarity) {
        this.name = name;
        this.type = type;
        this.rarity = rarity;
    }

    // Getter method to return the name of the collectible
    public String getName() { 
        return name; 
    }

    // Getter method to return the type/category of the collectible
    public String getType() { 
        return type; 
    }

    // Getter method to return the rarity level
    public int getRarity() { 
        return rarity; 
    }

    // This method provides a readable string version of the object.
    // It overrides the default toString() method so we can print something like:
    // "Phoenix Flame [Fire] (Rarity: 5)"
    public String toString() {
        return name + " [" + type + "] (Rarity: " + rarity + ")";
    }
}

// This line would be used in an interactive notebook or learning environment
// to run a main method from another class called Main.
Main.main(null);
Phoenix Flame [Fire] (Rarity: 5)
Aqua Sprite [Water] (Rarity: 3)
Blazing Ember [Fire] (Rarity: 2)
Number of Fire-type items: 2

Key components:

  • Encapsulation: Fields are marked private to prevent direct modification from outside the class. Access is controlled using getter methods.
  • Constructor: Makes it easy to create new Collectible objects with specific values. Custom toString(): Helps print the object in a human-readable way.
  • Use Case: This class could be used in a collection (like a List or Set) to build and manage a collection of unique or rare items.

Part 2: Create an Inventory Class

import java.util.ArrayList; // Import the ArrayList class from the Java Collections Framework

// This class represents an inventory that stores a collection of Collectible items
public class Inventory {
    // Field: a dynamic list to store Collectible objects
    private ArrayList<Collectible> items;

    // Constructor: initializes the ArrayList when an Inventory object is created
    public Inventory() {
        items = new ArrayList<>();
    }

    // Adds a new Collectible item to the inventory
    public void addItem(Collectible c) {
        items.add(c); // Uses ArrayList's add() method
    }

    // Displays all Collectibles in the inventory
    public void showInventory() {
        for (Collectible c : items) {
            System.out.println(c); // Each Collectible's toString() method is called here
        }
    }

    // Counts how many items in the inventory match a given type (case-insensitive)
    public int countByType(String type) {
        int count = 0;
        for (Collectible c : items) {
            if (c.getType().equalsIgnoreCase(type)) {
                count++;
            }
        }
        return count; // Returns the total number of matching items
    }
}

// Runs the main method from another class named Main
Main.main(null);
Phoenix Flame [Fire] (Rarity: 5)
Aqua Sprite [Water] (Rarity: 3)
Blazing Ember [Fire] (Rarity: 2)
Number of Fire-type items: 2

Key components:

  • ArrayList: A resizable list that holds all the Collectible objects (items field).
  • Encapsulation: Inventory hides the items list and provides methods to work with it.
  • Loops and Accessors: for-each loop is used to iterate through the list using getter methods.
  • Case-insensitive comparison: .equalsIgnoreCase() allows counting items regardless of text case.
  • Object-Oriented Design: The class interacts with another class (Collectible), modeling real-world systems.

Part 3: Main Program Logic

public class Main {
    public static void main(String[] args) {
        // Create a new Inventory instance
        Inventory myInventory = new Inventory();

        // Create some Collectible objects with different types and rarities
        Collectible card1 = new Collectible("Phoenix Flame", "Fire", 5);
        Collectible card2 = new Collectible("Aqua Sprite", "Water", 3);
        Collectible card3 = new Collectible("Blazing Ember", "Fire", 2);

        // Add each Collectible to the inventory
        myInventory.addItem(card1);
        myInventory.addItem(card2);
        myInventory.addItem(card3);

        // Display all items currently in the inventory
        myInventory.showInventory();

        // Count and display how many items are of the "Fire" type
        System.out.println("Number of Fire-type items: " + myInventory.countByType("Fire"));
    }
}

// Runs the main method to execute the program in a notebook or REPL-style environment
Main.main(null);
Phoenix Flame [Fire] (Rarity: 5)
Aqua Sprite [Water] (Rarity: 3)
Blazing Ember [Fire] (Rarity: 2)
Number of Fire-type items: 2

Key components:

  • Object Creation: New instances of Collectible are created with constructor values.
  • Method Calls: addItem(), showInventory(), and countByType() are called to interact with data.
  • Dynamic Storage: The ArrayList inside Inventory allows easy scaling as more items are added.
  • Encapsulation: The user of the class (in Main) doesn’t need to know how the ArrayList works internally.

Homework:

List Task: Modify your my_collection list to support bulk adding and removal of items using another list. • Create a method that takes a list of new items and adds them all to my_collection. • Create another method that removes all items in a given list from my_collection.

Dictionary Task: Modify your item_details dictionary to support value updates and rarity-based filters. • Add a method to update an item’s value by a percentage (e.g., increase all epic items by 10%). • Create a method that filters and returns all items of a given rarity.

Set Task: Add set-based tracking of items. • Use a traded_items set and a duplicate_items set. • Add a method that checks if any new item being added is already in the collection, and if so, log it in duplicate_items. • Ensure no duplicates are added to the main list.

Print Method: Create a method to display the full collection, showing: • Item name • Rarity • Value Format the output cleanly (like a table or aligned print).

Bonus Challenge: Create a method that uses a stack to simulate nested inventory folders (e.g., Weapon > Magic > Fire > Scroll). • Track your current folder path with a stack. • Allow going “deeper” and “back up” in the folder structure with push/pop. • Print the full current path using the stack.

Sample Code Snippet:

Stack<String> folderStack = new Stack<>();
folderStack.push("Weapons");
folderStack.push("Magic");
folderStack.push("Fire");

System.out.println(String.join(" > ", folderStack));  // Output: Weapons > Magic > Fire

folderStack.pop(); // back out of Fire
System.out.println(String.join(" > ", folderStack));  // Output: Weapons > Magic
Weapons > Magic > Fire
Weapons > Magic