An expense importer receives compact lines such as travel:120. The legacy implementation treats parsing, business validation, and bookkeeping as one operation. It handles a few happy paths, but it accepts unknown categories and expenses above the company limit because the import rules have no clear owner.
Refactor the starter code while preserving the public ExpenseImporter API:
ExpenseImporter() creates an importer with an empty ledger.boolean importLine(String line) imports one expense and returns whether it was accepted."<category>:<amount>", where the amount is a base-10 integer."travel", "meals", and "supplies".1 and 5000 inclusive.int acceptedCount() returns the number of expenses in the ledger.int rejectedCount() returns how many import attempts were malformed or violated the policy.int total() returns the sum of all accepted expenses.int categoryTotal(String category) returns the accepted total for that category, or 0 when none exists.Parsing answers “can this text become an expense?” Policy validation answers “does the company allow this expense?” Storage happens only after both answers are yes.
Input:
Output:
Explanation: Both lines are well formed and satisfy the expense policy, so they reach the ledger.
Input:
Output:
Explanation: The first line parses, but its category is not allowed. The second has a valid category but an invalid amount. Neither belongs in the ledger.
0 <= line.length <= 600 <= category.length <= 30100 calls will be made across all methods.The starter keeps every concern in one class. It also implements only part of the company policy, so refactoring includes restoring the missing rules.
Full marks when parsing, policy validation, and accepted-expense storage live in separate types coordinated by ExpenseImporter. Lose points heavily when one method owns the file syntax, business rules, and ledger updates.
Full marks when malformed and policy-rejected lines increment the rejected count exactly once and never reach the ledger. Lose points when partially parsed data is stored or rejected data affects totals.
Full marks when the policy is the only place that knows allowed categories and amount limits, while the ledger alone owns accepted totals. Lose points for duplicated rules or separate counters that can drift from ledger contents.
Passing every test is not enough on its own. A submission is accepted only when the design also clears the bar.
| Call | Returns |
|---|---|
| new ExpenseImporter() | null |
| importLine("travel:120") | true |
| importLine("meals:30") | true |
| acceptedCount() | 2 |
| rejectedCount() | 0 |
| total() | 150 |
| categoryTotal("travel") | 120 |
Both lines are well formed and satisfy the expense policy, so they reach the ledger.
Run checks these cases. Submit also runs a larger hidden set.

