--- title: "Jam 06 - Exercise 1" tags: - 2 ๐Ÿ“ in writing - 3 ๐Ÿงช in testing - 4 ๐Ÿฅณ done - classes - uml - exceptions - enums --- <!-- markdownlint-disable line-length single-h1 no-inline-html --> <!-- markdownlint-configure-file { "ul-indent": { "indent": 4 }, "link-fragments": {"ignore_case": true} } --> {%hackmd dJZ5TulxSDKme-3fSY4Lbw %} # Getting Started Before diving into the exercises, create your workspace for this jam: 1. Make sure you have committed all previous work and merged it into the `main` branch 2. Create and switch to a new feature branch called `jam06` 3. Set up your source directory at `src/main/java/jam06` 4. Set up your test directory at `src/test/java/jam06` :::info ๐Ÿ”ง **Quick Setup Reference** - Remember to verify your working directory is clean before creating the branch (git status has no red or green files) - You can always check your current branch in IntelliJ's bottom-right corner - If you need a refresher on any git commands, refer to Jam 01's documentation ::: Now that we have our workspace set up and our feature branch created, we're ready to start designing our cash register system! # Exercise 1 - Advanced Enum Types & Testing ## Overview - Exercise 1 In this exercise, you'll learn about Java's powerful enumerated types (enums) by implementing a `Money` enum that will be used throughout our cash register system. Enums in Java are much more than just constants - they're full-fledged classes that can have constructors, fields, and methods. This makes them perfect for representing fixed sets of values with associated behavior, like currency denominations in our case. :::info ๐Ÿ”‘ **Key Concepts** - Enums as type-safe constants - Adding behavior to enum types - Test-driven development - Currency representation in software ::: ## The Problem - Exercise 1 **Problem**: Our cash register needs to handle U.S. currency denominations and perform various money-related calculations. We need a robust way to: 1. Represent different currency denominations (penny through hundred-dollar bill) 2. Convert between cents and dollars 3. Calculate totals and make change 4. Prevent invalid currency operations This is a perfect use case for an enum, as: - There's a fixed set of valid currency denominations - Each denomination has an associated value - We need to perform calculations with these values - We want to prevent invalid currency values ## Understanding Java Enums Before we implement our `Money` enum, let's understand what makes Java enums special: 1. **Basic Enum Structure**: ```java= public enum SimpleExample { FIRST, SECOND, THIRD; // These are enum constants } ``` 2. **Enums with Values - Making Them More Interesting!** Let's make our enums more exciting by giving them some personality! Just like how each day of the week has its own special number (Monday is day 1, Tuesday is day 2, etc.), we can give our enum constants their own values. Here's a fun example: ```java= public enum DayOfWeek { MONDAY(1), // Case of the Mondays... TUESDAY(2), // Taco Tuesday! WEDNESDAY(3); // Hump daaaay private final int dayNumber; // Each day needs to remember its number // This is like a birthday - each day gets assigned its number when created DayOfWeek(int dayNumber) { this.dayNumber = dayNumber; } // When someone asks "what number day are you?", we can tell them public int getDayNumber() { return dayNumber; } } ``` Let's break down what's happening here: 1. Each enum constant (MONDAY, TUESDAY, etc.) gets a value in parentheses - this is like giving each day its ID badge 2. We store that value in a `private final` field - it's private because it's personal, and final because days don't change their number! 3. The constructor (DayOfWeek) takes that value and saves it. 4. A getter method lets us peek at that value whenever we need it - like asking "Hey Monday, what number are you?" This pattern is super useful when your enum constants need to carry around extra information. 3. **Custom Methods - Teaching Enums New Tricks!** Just like how each day of the week might have special activities, we can teach our enum constants to do special things using custom methods. Let's expand our `DayOfWeek` example: ```java= public enum DayOfWeek { MONDAY(1, "Case of the Mondays..."), TUESDAY(2, "Taco Tuesday!"), WEDNESDAY(3, "The Week is mid"), THURSDAY(4, "Almost Friday!"), FRIDAY(5, "TGIF!"), SATURDAY(6, "Weekend vibes!"), SUNDAY(7, "Sunday funday!"); private final int dayNumber; private final String catchPhrase; DayOfWeek(int dayNumber, String catchPhrase) { this.dayNumber = dayNumber; this.catchPhrase = catchPhrase; } // Basic getter methods public int getDayNumber() { return dayNumber; } // Fun custom methods! public boolean isWeekend() { return this == SATURDAY || this == SUNDAY; } public String getGreeting() { return "Happy " + this.name() + "! " + catchPhrase; } public DayOfWeek getNextDay() { // Get all possible days in an array DayOfWeek[] days = DayOfWeek.values(); // Find the next day (or loop back to Monday) int nextIndex = (this.ordinal() + 1) % days.length; return days[nextIndex]; } // Static methods work too! public static DayOfWeek getRandomDay() { DayOfWeek[] days = values(); int randomIndex = (int)(Math.random() * days.length); return days[randomIndex]; } } ``` Let's see what cool things we can do with these methods (You can see this code live at [onlinegdb.com/Gucy_8xIo](https://onlinegdb.com/Gucy_8xIo)): ```java= // Get today's ordinal (0-6, where Monday=0) int dayIndex = LocalDate.now().getDayOfWeek().ordinal(); // Example comments below assume today is Wednesday // Use that index to get our matching enum constant DayOfWeek today = DayOfWeek.values()[dayIndex]; // Using our custom methods System.out.println("Greeting is: " + today.getGreeting()); // Prints: "Happy WEDNESDAY! Hump daaaay" System.out.println("Next Day is: " + today.getNextDay()); // Prints: "THURSDAY" System.out.println("Is weekend: " + today.isWeekend()); // Prints: "false" // Using our static method DayOfWeek surprise = DayOfWeek.getRandomDay(); // Gets a random day! System.out.println("Random Day ordinal: " + surprise.getDayNumber()); // We can even chain methods together System.out.println(today.getNextDay().getNextDay().getGreeting()); // Prints: "Happy 'FRIDAY'! TGIF!" ``` Some cool things to notice about enum methods: 1. **Constructors**: Notice how the: - constructor parameters (`DayOfWeek(int dayNumber, String catchPhrase)`) - match the enum constant arguments (`MONDAY(1, "Case of the Mondays...")`) 2. **Instance Methods**: Each enum constant can use these methods to do its own thing (like `getGreeting()`) 3. **Static Methods**: Work for the whole enum type (like `getRandomDay()`) and is not specific to any one enum. 4. **Built-in Methods**: Enums come with some handy methods already: - `name()`: Gets the exact name of the constant - `ordinal()`: Gets its position in the enum (starting at 0) - `values()`: Gets an array of all constants (We used this above to set `today` to the current day since the index of Monday in `LocalDate.now().getDayOfWeek().ordinal()` is the same as the index of MONDAY in `DayOfWeek.values()` and so on.) - `valueOf(String)`: Converts a string to the matching enum constant This makes enums super powerful - they're not just simple constants anymore, but can have their own behaviors and personality! ๐ŸŽ‰ :::info ๐Ÿ’ก **Pro Tip**: When designing enum methods, think about what would make sense for ALL constants to be able to do. If a method only makes sense for some constants but not others, it might be a sign to rethink your design! ::: :::success ๐Ÿ”ง **Key Features of Java Enums** 1. Type Safety - Can't create new instances - Can't use invalid values - Compile-time checking 2. Instance Fields - Each constant can have data - Fields must be final - Set through constructor 3. Methods - Can have instance methods - Can have static methods - Can override toString() 4. Constructors - Must be private - Called once per constant - Can't be called directly ::: ## Implementation Task Now it's time to implement the `Money` enum! First, get the test file that will guide your implementation: ```bash # You may need to create the directory first: # If working on your laptop (replace userid with your Bucknell username): scp "userid@linuxremote.bucknell.edu:/home/csci205/2025-spring/student/jam06/MoneyTest.java" src/test/java/jam06/ # If working on linuxremote: cp "/home/csci205/2025-spring/student/jam06/MoneyTest.java" src/test/java/jam06/ ``` ### ๐Ÿšง Detour: Acceptance Test-Driven Development Take a moment to review the test file. Notice how it: - Tests all currency denominations (PENNY through HUNDRED) - Verifies correct values in cents - Validates proper string formatting (ยข for coins, $ for bills) - Checks enum constant ordering This scenario mirrors a common practice in professional software development where a requirements or quality assurance team writes tests before any implementation begins. These "acceptance tests" serve as executable specifications, clearly defining how the code should behave. This approach, sometimes called "Acceptance Test-Driven Development" (ATDD), helps ensure that developers build exactly what the business needs. In Jam 05, you worked with provided tests in a similar way, incrementally uncommenting them to guide your implementation. Here again, like in many professional environments, the tests are provided to you as part of the requirements. Let's examine the tradeoffs of ATDD from a professional software development perspective: Advantages: - Provides clear acceptance criteria and requirements upfront - Enables rapid development feedback loops and continuous validation - Enforces modular design by requiring testable components - Creates a reliable safety net for future code changes - Serves as living documentation of system behavior - Reduces bugs in production by catching issues early - Facilitates collaboration between developers and stakeholders by defining the classes/states/behaviors at an abstract level Disadvantages: - Requires significant upfront investment in test creation - Can constrain innovative or exploratory development approaches - May miss edge cases not anticipated during test writing - Increases initial development time and complexity - Creates maintenance overhead as tests must be kept up-to-date - Can lead to over-testing of simple functionality - May require refactoring tests as requirements evolve ## Required Steps - Implementing the Money Enum Create a new file called `Money.java` in your `jam06` package and implement the enum according to the test specifications. Consider these design points: 1. **Design Questions** - What values should each denomination represent? - How should you store the denomination's value? - What methods will you need to work with the values? - How should you format the string representation? - How will you handle the difference between coins and bills? 2. **Implementation Strategy** - Review the test file to understand all requirements - Plan your enum constant ordering (coins then bills) - Use test failures to guide your implementation - Think about value storage and formatting 3. **Testing Cycle** - Run the tests - Read the failure messages - Implement the missing functionality - Repeat until tests pass ๐Ÿ’ก **Tips for Implementation** - Use the DayOfWeek example to help you understand how to implement the Money enum. - Remember that enum constructors must be private - Store all values in cents for consistency - Consider using a threshold to determine ยข vs $ formatting - Use the test file as your complete specification - Think about how to handle both coins and bills elegantly :::warning ๐Ÿšจ **Common Implementation Pitfalls** - Don't change the test file - Make sure your enum values match exactly - Check string formatting for both coins and bills - Verify all denomination relationships - Ensure proper value handling in cents - Follow the test specifications ::: > ๐Ÿ” **Checkpoint** > > Before proceeding, verify: > > - All enum constants are defined with correct values > - Constructor and fields are properly implemented > - All methods are implemented and documented > - All tests pass with green checkmarks in IntelliJ's test runner > - No exceptions or errors are shown in the console output > - The toString() method correctly formats coins with ยข and bills with $ ## Save Your Work - Exercise 1 **Run all tests to verify your implementation**: - Right click on the test folder in IntelliJ - Click on `Run tests in 'csci205_jams` - Ensure all tests pass before continuing **Stage your changes**: ```bash git add src/main/java/jam06/Money.java src/test/java/jam06/MoneyTest.java .idea/. ``` **Verify what files are still uncommitted (no red files/folders)**: ```bash git status # Resolve any red files/folders ``` **Commit your work**: ```bash git commit -m "jam06: Implement Money enum with tests" ``` **Your working directory should now be clean.** :::success ๐Ÿ”‘ **Key Takeaways** - Java enums are powerful classes that can have fields, methods, and constructors - Enums provide type safety for fixed sets of values - Test-driven development helps ensure correct implementation - Good documentation is crucial for enum usability :::