Handling Errors Using Exceptions

本文探讨了Java中错误处理的重要性,并介绍了如何通过合理使用检查性和非检查性异常来提高程序的可读性、可靠性和可维护性。文章还提供了一些关于如何设计API以更好地处理异常的建议。
Everyone tries to avoid them, but it's an unfortunate fact: [b]Errors occur in software programs. However, if you handle errors properly, you'll greatly improve programs' readability, reliability and maintainability. The Java programming language uses exceptions for error handling.[/b]
[b]What Is an Exception?[/b]
An exception is an event that occurs during the execution of a program that disrupts the normal flow of instructions.

[b]The Catch or Specify Requirement [/b]
There are two kinds of exceptions: checked exceptions and un-checked exceptions.
it is the bottom line guildline:If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception.

[b]Best Practices for Designing the API[/b]
1.When deciding on checked exceptions vs. unchecked exceptions, ask yourself, "What action can the client code take when the exception occurs?"
Moreover, prefer unchecked exceptions for all programming errors: unchecked exceptions have the benefit of not forcing the client API to explicitly deal with them. They propagate to where you want to catch them, or they go all the way out and get reported.

2.Preserve encapsulation.
Never let implementation-specific checked exceptions escalate to the higher layers. For example, do not propagate SQLException from data access code to the business objects layer. Business objects layer do not need to know about SQLException. You have two options:

>Convert SQLException into another checked exception, if the client code is expected to recuperate from the exception.
>Convert SQLException into an unchecked exception, if the client code cannot do anything about it.
a recommended way is:
public void dataAccessCode(){
try{
..some code that throws SQLException
}catch(SQLException ex){
throw new RuntimeException(ex);
}
not:
public void dataAccessCode(){
try{
..some code that throws SQLException
}catch(SQLException ex){
ex.printStacktrace();
}
}
for the last one, client can do nothing, so we can throw it to upper tier to let him/her know what had happened.

3. how to throw exceptions?
for those checked exceptions, such as Integer.parseInt("ABC"), I/O exception. we can catch it on the business level, deal it with a default manner or throw it to the upper tier(by convert it to a recognised exception) which have the ability to deal with it.
for those unchecked exceptions, throw it to upper tier to deal with.
内容概要:本文介绍了一种基于蒙特卡洛模拟和拉格朗日优化方法的电动汽车充电站有序充电调度策略,重点针对分时电价机制下的分散式优化问题。通过Matlab代码实现,构建了考虑用户充电需求、电网负荷平衡及电价波动的数学模【电动汽车充电站有序充电调度的分散式优化】基于蒙特卡诺和拉格朗日的电动汽车优化调度(分时电价调度)(Matlab代码实现)型,采用拉格朗日乘子法处理约束条件,结合蒙特卡洛方法模拟大量电动汽车的随机充电行为,实现对充电功率和时间的优化分配,旨在降低用户充电成本、平抑电网峰谷差并提升充电站运营效率。该方法体现了智能优化算法在电力系统调度中的实际应用价值。; 适合人群:具备一定电力系统基础知识和Matlab编程能力的研究生、科研人员及从事新能源汽车、智能电网相关领域的工程技术人员。; 使用场景及目标:①研究电动汽车有序充电调度策略的设计与仿真;②学习蒙特卡洛模拟与拉格朗日优化在能源系统中的联合应用;③掌握基于分时电价的需求响应优化建模方法;④为微电网、充电站运营管理提供技术支持和决策参考。; 阅读建议:建议读者结合Matlab代码深入理解算法实现细节,重点关注目标函数构建、约束条件处理及优化求解过程,可尝试调整参数设置以观察不同场景下的调度效果,进一步拓展至多目标优化或多类型负荷协调调度的研究。
内容概要:本文围绕面向制造业的鲁棒机器学习集成计算流程展开研究,提出了一套基于Python实现的综合性计算框架,旨在应对制造过程中数据不确定性、噪声干扰面向制造业的鲁棒机器学习集成计算流程研究(Python代码实现)及模型泛化能力不足等问题。该流程集成了数据预处理、特征工程、异常检测、模型训练与优化、鲁棒性增强及结果可视化等关键环节,结合集成学习方法提升预测精度与稳定性,适用于质量控制、设备故障预警、工艺参数优化等典型制造场景。文中通过实际案例验证了所提方法在提升模型鲁棒性和预测性能方面的有效性。; 适合人群:具备Python编程基础和机器学习基础知识,从事智能制造、工业数据分析及相关领域研究的研发人员与工程技术人员,尤其适合工作1-3年希望将机器学习应用于实际制造系统的开发者。; 使用场景及目标:①在制造环境中构建抗干扰能力强、稳定性高的预测模型;②实现对生产过程中的关键指标(如产品质量、设备状态)进行精准监控与预测;③提升传统制造系统向智能化转型过程中的数据驱动决策能力。; 阅读建议:建议读者结合文中提供的Python代码实例,逐步复现整个计算流程,并针对自身业务场景进行数据适配与模型调优,重点关注鲁棒性设计与集成策略的应用,以充分发挥该框架在复杂工业环境下的优势。
Thanks to your work so far, the library now has a functioning system. However, librarians have reported that some records in the CSV files are corrupted with invalid values. This has caused misbehaviour in the system, sometimes even crashing during busy exam periods, creating unnecessary stress for students. In real-world software engineering, robustness and correctness are just as important as functionality. Programs must gracefully handle unexpected situations and invalid inputs without failing. Two key approaches developers use are: Assertions: Internal checks that validate assumptions made by the programmer (e.g., "This variable should never be negative"). Assertions are mainly used during development and debugging. Defensive programming: Validates inputs and usage patterns to prevent invalid or unexpected behaviour at runtime. This includes checking for correct types, value ranges, and providing helpful error messages when something goes wrong. Description In this task, you will extend your library system by adding custom error handling to make it more robust. Python already raises built-in errors, but here you must define and use custom exceptions (in custom_errors.py) to handle library-specific error conditions. Building upon Task 3, update your user.py and book.py modules to handle invalid input, and modify task4.py to handle exceptions gracefully so that the system does not crash. You must ensure that this system is: Correct: Through use of assert to validate assumptions in your logic. Safe: Through defensive programming techniques that prevent invalid inputs (e.g. wrong types, negative amounts). In this task we will be using custom errors as python will already raise some of these errors when we execute invalid code. Our new errors are located in cusom_errors.py. You must use these custom errors, please see rubric for related penalties in this task. After auditing the CSV data, the librarian has introduced new validation rules to be applied in addition to the requirements described in Tasks 1–3. These rules strengthen data quality and prevent corrupted records from entering the system. Always include a helpful and descriptive error message when raising errors. Doing so contributes to the readability and overall quality of your assignment. Users Every user must have a password. Passwords cannot be empty. Every word in a user's name must contain only alphabetic characters. Numbers, symbols, and special characters are not allowed. Department is mandatory for students and staff, but must remain empty for other users. The only valid departments are: IT, Business, Arts, Science, Engineering, Education, Medicine and Library. Books The library only recognizes two valid book types: physical and online. The following fields are required for all books: Title, Author, Year Each book may have at most 5 keywords. Each word in keywords must consist of letters and numbers only. The only allowed special character is the hyphen (-). Loans Every loan record must be associated with an existing user and an existing book. The due date is a required field and cannot be left empty. Defensive Programming The following exceptions are provided to you in custom_errors.py: CustomTypeError: A value is the wrong type (e.g. a string instead of a float or int). CustomValueError: A value is of the correct type but invalid (e.g. negative copies). CustomDateError: Raised when a date is in the wrong format or when the date logic is invalid (e.g., borrow date occurs in the future). MissingRequiredFieldError: Raised when a required field is missing. UserNotFoundError or BookNotFoundError: Raised when a loan references a user or book that does not exist. CustomOperationError : Raised when an invalid borrow or return action is attempted. CustomLimitError: Raised when a user exceeds their quota or borrowing limit. CustomKeyError: Occurs when you try to access a key in the dictionary that doesn't exist.
10-18
```python # custom_errors.py class CustomTypeError(Exception): """Raised when a value is of the wrong type.""" pass class CustomValueError(Exception): """Raised when a value is of correct type but invalid.""" pass class CustomDateError(Exception): """Raised when a date is in wrong format or logically invalid.""" pass class MissingRequiredFieldError(Exception): """Raised when a required field is missing.""" pass class UserNotFoundError(Exception): """Raised when a user does not exist.""" pass class BookNotFoundError(Exception): """Raised when a book does not exist.""" pass class CustomOperationError(Exception): """Raised when an invalid borrow/return operation is attempted.""" pass class CustomLimitError(Exception): """Raised when a borrowing limit is exceeded.""" pass class CustomKeyError(Exception): """Raised when trying to access a non-existent key.""" pass ``` --- ### ✅ **Updated `user.py` with Defensive Programming and Assertions** ```python # user.py from datetime import datetime from custom_errors import CustomTypeError, CustomValueError, MissingRequiredFieldError class User: VALID_DEPARTMENTS = {"IT", "Business", "Arts", "Science", "Engineering", "Education", "Medicine", "Library"} def __init__(self, user_id: str, name: str, user_type: str, department: str = "", password: str = ""): # Type checks if not isinstance(user_id, str): raise CustomTypeError(f"User ID must be a string. Got {type(user_id).__name__}.") if not isinstance(name, str): raise CustomTypeError(f"Name must be a string. Got {type(name).__name__}.") if not isinstance(user_type, str): raise CustomTypeError(f"User type must be a string. Got {type(user_type).__name__}.") if not isinstance(department, str): raise CustomTypeError(f"Department must be a string. Got {type(department).__name__}.") if not isinstance(password, str): raise CustomTypeError(f"Password must be a string. Got {type(password).__name__}.") # Required fields if not user_id.strip(): raise MissingRequiredFieldError("User ID cannot be empty.") if not name.strip(): raise MissingRequiredFieldError("Name cannot be empty.") if not user_type.strip(): raise MissingRequiredFieldError("User type cannot be empty.") if not password.strip(): raise MissingRequiredFieldError("Password cannot be empty.") # Validate name: each word must be alphabetic only for word in name.strip().split(): if not word.isalpha(): raise CustomValueError(f"Name contains invalid word &#39;{word}&#39;. Only alphabetic characters are allowed.") # Department logic if user_type.lower() in ["student", "staff"]: if not department.strip(): raise MissingRequiredFieldError(f"Department is required for {user_type}.") dept = department.strip() if dept not in self.VALID_DEPARTMENTS: raise CustomValueError(f"Invalid department: &#39;{dept}&#39;. Valid options: {&#39;, &#39;.join(sorted(self.VALID_DEPARTMENTS))}") else: if department.strip(): raise CustomValueError(f"Only students and staff can have a department. Found &#39;{department}&#39; for {user_type}.") # Assign attributes self.user_id = user_id.strip() self.name = name.strip() self.user_type = user_type.strip().lower() self.department = department.strip() if department else "" self.password = password # Already checked non-empty above self.borrowed_books = [] # Assert internal consistency assert isinstance(self.user_id, str) and len(self.user_id) > 0, "User ID failed post-initialization validation." assert isinstance(self.name, str) and len(self.name) > 0, "Name failed post-initialization validation." assert self.user_type in ["student", "staff", "other"], f"Unexpected user_type after init: {self.user_type}" def can_borrow(self) -> bool: max_books = 5 if self.user_type == "student" else 10 return len(self.borrowed_books) < max_books def borrow_book(self, book): from book import Book # Avoid circular import if not isinstance(book, Book): raise CustomTypeError(f"Expected Book object, got {type(book).__name__}.") if not self.can_borrow(): raise CustomLimitError(f"{self.name} has reached the borrowing limit ({len(self.borrowed_books)} books).") self.borrowed_books.append(book) def return_book(self, book): if book not in self.borrowed_books: raise CustomOperationError(f"{self.name} does not have book &#39;{book.title}&#39;. Cannot return.") self.borrowed_books.remove(book) def __repr__(self): return f"User(ID={self.user_id}, Name=&#39;{self.name}&#39;, Type=&#39;{self.user_type}&#39;, Dept=&#39;{self.department}&#39;)" ``` --- ### ✅ **Updated `book.py` with Defensive Programming and Assertions** ```python # book.py from custom_errors import CustomTypeError, CustomValueError, MissingRequiredFieldError class Book: VALID_TYPES = ("physical", "online") def __init__(self, isbn: str, title: str, author: str, year: int, book_type: str, keywords: list = None): # Type checks if not isinstance(isbn, str): raise CustomTypeError(f"ISBN must be a string. Got {type(isbn).__name__}.") if not isinstance(title, str): raise CustomTypeError(f"Title must be a string. Got {type(title).__name__}.") if not isinstance(author, str): raise CustomTypeError(f"Author must be a string. Got {type(author).__name__}.") if not isinstance(year, int): raise CustomTypeError(f"Year must be an integer. Got {type(year).__name__}.") if not isinstance(book_type, str): raise CustomTypeError(f"Book type must be a string. Got {type(book_type).__name__}.") if keywords is not None and not isinstance(keywords, list): raise CustomTypeError(f"Keywords must be a list or None. Got {type(keywords).__name__}.") # Required fields if not isbn.strip(): raise MissingRequiredFieldError("ISBN cannot be empty.") if not title.strip(): raise MissingRequiredFieldError("Title cannot be empty.") if not author.strip(): raise MissingRequiredFieldError("Author cannot be empty.") if year < 1000 or year > datetime.now().year: raise CustomValueError(f"Year must be between 1000 and current year. Got {year}.") if book_type.lower() not in self.VALID_TYPES: raise CustomValueError(f"Invalid book type: &#39;{book_type}&#39;. Must be one of {self.VALID_TYPES}.") # Keywords validation keywords = keywords or [] if len(keywords) > 5: raise CustomLimitError(f"A book can have at most 5 keywords. Got {len(keywords)}.") for kw in keywords: if not isinstance(kw, str): raise CustomTypeError(f"Keyword must be a string. Got {type(kw).__name__}.") if not kw.strip(): raise CustomValueError("Keywords cannot be empty.") # Only letters, digits, and hyphens allowed if not all(c.isalnum() or c == &#39;-&#39; for c in kw): raise CustomValueError(f"Invalid keyword &#39;{kw}&#39;. Only letters, numbers, and hyphens are allowed.") # Assign values self.isbn = isbn.strip() self.title = title.strip() self.author = author.strip() self.year = year self.type = book_type.lower() self.keywords = [kw.strip() for kw in keywords] # Assert internal state assert isinstance(self.isbn, str) and len(self.isbn) > 0, "ISBN validation failed after assignment." assert isinstance(self.title, str) and len(self.title) > 0, "Title validation failed after assignment." assert isinstance(self.author, str) and len(self.author) > 0, "Author validation failed after assignment." assert self.year >= 1000 and self.year <= datetime.now().year, "Year out of range after assignment." assert self.type in self.VALID_TYPES, "Book type invalid after assignment." assert len(self.keywords) <= 5, "Too many keywords stored." def matches_keyword(self, keyword: str) -> bool: if not isinstance(keyword, str): raise CustomTypeError(f"Keyword to match must be a string. Got {type(keyword).__name__}.") return any(keyword.lower() in kw.lower() for kw in self.keywords) def __repr__(self): return f"Book(ISBN={self.isbn}, Title=&#39;{self.title}&#39;, Author=&#39;{self.author}&#39;, Year={self.year}, Type=&#39;{self.type}&#39;)" ``` --- ### ✅ **Updated `task4.py` – Robust Main Program with Exception Handling** ```python # task4.py import csv from datetime import datetime from custom_errors import ( MissingRequiredFieldError, CustomTypeError, CustomValueError, UserNotFoundError, BookNotFoundError, CustomDateError, CustomOperationError, CustomLimitError ) from user import User from book import Book class LibrarySystem: def __init__(self): self.users = {} # user_id -> User self.books = {} # isbn -> Book self.loans = {} # isbn -> (user_id, due_date) def load_users(self, filename): try: with open(filename, newline=&#39;&#39;, encoding=&#39;utf-8&#39;) as file: reader = csv.DictReader(file) for line_num, row in enumerate(reader, start=2): # Start at 2 because header is line 1 try: user_id = row.get(&#39;user_id&#39;, &#39;&#39;).strip() name = row.get(&#39;name&#39;, &#39;&#39;).strip() user_type = row.get(&#39;user_type&#39;, &#39;&#39;).strip() department = row.get(&#39;department&#39;, &#39;&#39;).strip() password = row.get(&#39;password&#39;, &#39;&#39;).strip() if not all([user_id, name, user_type, password]): raise MissingRequiredFieldError(f"Missing required field(s) in row {line_num}: {row}") user = User(user_id, name, user_type, department, password) self.users[user_id] = user except (CustomTypeError, CustomValueError, MissingRequiredFieldError) as e: print(f"[Line {line_num}] Error loading user: {e}") except Exception as e: print(f"[Line {line_num}] Unexpected error: {e}") except FileNotFoundError: print(f"Error: File &#39;{filename}&#39; not found.") except Exception as e: print(f"Error reading users file: {e}") def load_books(self, filename): try: with open(filename, newline=&#39;&#39;, encoding=&#39;utf-8&#39;) as file: reader = csv.DictReader(file) for line_num, row in enumerate(reader, start=2): try: isbn = row.get(&#39;isbn&#39;, &#39;&#39;).strip() title = row.get(&#39;title&#39;, &#39;&#39;).strip() author = row.get(&#39;author&#39;, &#39;&#39;).strip() year_str = row.get(&#39;year&#39;, &#39;&#39;).strip() book_type = row.get(&#39;type&#39;, &#39;&#39;).strip() keywords_str = row.get(&#39;keywords&#39;, &#39;&#39;).strip() if not all([isbn, title, author, year_str, book_type]): raise MissingRequiredFieldError(f"Missing required field(s) in row {line_num}: {row}") try: year = int(year_str) except ValueError: raise CustomTypeError(f"Year must be an integer. Got &#39;{year_str}&#39;.") keywords = [kw.strip() for kw in keywords_str.split(",")] if keywords_str else [] book = Book(isbn, title, author, year, book_type, keywords) self.books[isbn] = book except (CustomTypeError, CustomValueError, MissingRequiredFieldError, CustomLimitError) as e: print(f"[Line {line_num}] Error loading book: {e}") except Exception as e: print(f"[Line {line_num}] Unexpected error: {e}") except FileNotFoundError: print(f"Error: File &#39;{filename}&#39; not found.") except Exception as e: print(f"Error reading books file: {e}") def load_loans(self, filename): try: with open(filename, newline=&#39;&#39;, encoding=&#39;utf-8&#39;) as file: reader = csv.DictReader(file) for line_num, row in enumerate(reader, start=2): try: user_id = row.get(&#39;user_id&#39;, &#39;&#39;).strip() isbn = row.get(&#39;isbn&#39;, &#39;&#39;).strip() due_date_str = row.get(&#39;due_date&#39;, &#39;&#39;).strip() if not all([user_id, isbn, due_date_str]): raise MissingRequiredFieldError(f"Missing required loan field(s) in row {line_num}.") # Validate date try: due_date = datetime.strptime(due_date_str, "%Y-%m-%d") if due_date.date() < datetime.now().date(): print(f"[Warning] Due date expired for loan: {isbn} -> {user_id}") except ValueError: raise CustomDateError(f"Invalid due date format: &#39;{due_date_str}&#39;. Use YYYY-MM-DD.") # Check existence if user_id not in self.users: raise UserNotFoundError(f"User ID &#39;{user_id}&#39; not found.") if isbn not in self.books: raise BookNotFoundError(f"ISBN &#39;{isbn}&#39; not found.") # Perform loan action user = self.users[user_id] book = self.books[isbn] if not user.can_borrow(): raise CustomLimitError(f"User &#39;{user.name}&#39; cannot borrow more books.") user.borrow_book(book) self.loans[isbn] = (user_id, due_date) except (UserNotFoundError, BookNotFoundError, CustomDateError, CustomLimitError, MissingRequiredFieldError, CustomOperationError) as e: print(f"[Line {line_num}] Error processing loan: {e}") except Exception as e: print(f"[Line {line_num}] Unexpected error: {e}") except FileNotFoundError: print(f"Error: File &#39;{filename}&#39; not found.") except Exception as e: print(f"Error reading loans file: {e}") def return_book(self, user_id: str, isbn: str): try: if user_id not in self.users: raise UserNotFoundError(f"User ID &#39;{user_id}&#39; not found.") if isbn not in self.books: raise BookNotFoundError(f"ISBN &#39;{isbn}&#39; not found.") if isbn not in self.loans: raise CustomOperationError(f"Book &#39;{isbn}&#39; is not currently on loan.") user = self.users[user_id] book = self.books[isbn] user.return_book(book) del self.loans[isbn] print(f"Book &#39;{book.title}&#39; returned successfully by {user.name}.") except (UserNotFoundError, BookNotFoundError, CustomOperationError) as e: print(f"Return failed: {e}") except Exception as e: print(f"Unexpected error during return: {e}") def search_books(self, keyword: str): try: if not keyword or not isinstance(keyword, str): raise CustomTypeError("Search keyword must be a non-empty string.") results = [book for book in self.books.values() if book.matches_keyword(keyword)] return results except Exception as e: print(f"Search error: {e}") return [] # Example usage if __name__ == "__main__": lib = LibrarySystem() lib.load_users("users.csv") lib.load_books("books.csv") lib.load_loans("loans.csv") print("\n--- Search Results for &#39;Python&#39; ---") for book in lib.search_books("Python"): print(book) print("\n--- Returning Book ---") lib.return_book("U003", "9780134685991") # Example return ``` --- ### 🔍 Explanation - **Custom Errors**: Defined in `custom_errors.py`, used consistently across modules. - **Defensive Input Validation**: - All inputs are checked for type (`isinstance`) and validity (e.g., department, name). - Empty passwords, invalid names, or malformed departments trigger appropriate exceptions. - **Assertions**: Used internally to ensure class invariants (e.g., user type is valid post-init). - **CSV Loading Resilience**: Each row is processed individually; errors are caught per-line to avoid full system crash. - **Loan System Integrity**: Validates due dates, existing users/books, and borrowing limits before creating loans. - **Graceful Degradation**: The system logs errors and continues instead of crashing. --- ### ✅ Summary of Key Improvements | Feature | Implemented | |-------|-------------| | Custom Exceptions | ✅ Used throughout | | Type Safety | ✅ `isinstance` checks | | Value Validation | ✅ Names, departments, years, keywords | | Required Fields | ✅ Enforced via `MissingRequiredFieldError` | | Max Keywords | ✅ Limited to 5 | | Loan Integrity | ✅ Checks user/book existence, due date | | Error Messages | ✅ Descriptive and helpful | | System Stability | ✅ No crashes on bad data | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值