简介
处理无效的用户输入是 Java 编程中的一个关键方面,它能确保你的应用程序保持健壮和可靠。当用户与你的程序进行交互时,他们可能会提供意外或错误的数据,如果处理不当,这些数据可能会导致你的应用程序崩溃。
在这个实验中,你将学习如何在 Java 应用程序中有效地处理无效的用户输入。你将探索不同的技术,从基本的错误检查到更高级的验证方法。在这个实验结束时,你将能够编写能够优雅地处理用户错误并提供适当反馈的 Java 程序。
处理无效的用户输入是 Java 编程中的一个关键方面,它能确保你的应用程序保持健壮和可靠。当用户与你的程序进行交互时,他们可能会提供意外或错误的数据,如果处理不当,这些数据可能会导致你的应用程序崩溃。
在这个实验中,你将学习如何在 Java 应用程序中有效地处理无效的用户输入。你将探索不同的技术,从基本的错误检查到更高级的验证方法。在这个实验结束时,你将能够编写能够优雅地处理用户错误并提供适当反馈的 Java 程序。
在第一步中,我们将创建一个简单的 Java 程序来收集用户输入。这将作为学习输入验证技术的基础。
Java 提供了多种从用户那里收集输入的方法。对于控制台应用程序,通常会使用 java.util
包中的 Scanner
类。这个类提供了读取不同类型输入的方法,例如整数、浮点数和字符串。
让我们先创建一个基本的 Java 程序,该程序会询问用户的年龄并将其打印出来。
首先,打开 WebIDE 并导航到项目目录:
通过点击 WebIDE 文件资源管理器中的“New File”图标来创建一个新文件。将文件命名为 UserInputDemo.java
在文件中添加以下代码:
import java.util.Scanner;
public class UserInputDemo {
public static void main(String[] args) {
// Create a Scanner object to read input
Scanner scanner = new Scanner(System.in);
// Prompt the user for their age
System.out.print("Please enter your age: ");
// Read the input
int age = scanner.nextInt();
// Display the entered age
System.out.println("You entered: " + age);
// Close the scanner
scanner.close();
}
}
按 Ctrl+S
或从菜单中选择“File” > “Save”来保存文件。
通过点击顶部菜单中的“Terminal” > “New Terminal”在 WebIDE 中打开一个终端。
javac UserInputDemo.java
java UserInputDemo
25
。你应该会看到以下输出:Please enter your age: 25
You entered: 25
现在,让我们看看当输入无效数据时会发生什么。再次运行程序:
java UserInputDemo
这次,输入一个非数字的值,例如 twenty-five
。你会看到类似以下的错误消息:
Please enter your age: twenty-five
Exception in thread "main" java.util.InputMismatchException
at java.base/java.util.Scanner.throwFor(Scanner.java:943)
at java.base/java.util.Scanner.next(Scanner.java:1598)
at java.base/java.util.Scanner.nextInt(Scanner.java:2263)
at java.base/java.util.Scanner.nextInt(Scanner.java:2217)
at UserInputDemo.main(UserInputDemo.java:12)
之所以会出现 InputMismatchException
异常,是因为程序期望的是数字输入(整数),但接收到的却是文本。程序崩溃了,而不是优雅地处理这种情况。在接下来的步骤中,我们将学习如何正确处理此类无效输入。
在这一步中,我们将修改程序,使用 Java 的异常处理机制来处理无效输入。
Java 中的异常是会打乱程序正常执行流程的事件。当用户输入无效数据时,Java 运行时系统会抛出一个异常,以表明出现了问题。程序可以捕获这些异常并进行适当处理,而不是崩溃。
Java 中异常处理的基本结构是 try-catch
块:
try {
// Code that might throw an exception
} catch (ExceptionType e) {
// Code to handle the exception
}
让我们更新程序,来处理用户输入非数字内容时出现的 InputMismatchException
异常:
在 WebIDE 中打开 UserInputDemo.java
文件。
修改代码以包含异常处理:
import java.util.Scanner;
import java.util.InputMismatchException;
public class UserInputDemo {
public static void main(String[] args) {
// Create a Scanner object to read input
Scanner scanner = new Scanner(System.in);
try {
// Prompt the user for their age
System.out.print("Please enter your age: ");
// Read the input
int age = scanner.nextInt();
// Display the entered age
System.out.println("You entered: " + age);
} catch (InputMismatchException e) {
// Handle the exception if non-numeric input is provided
System.out.println("Error: Please enter a valid numeric age.");
} finally {
// Close the scanner in the finally block to ensure it always gets closed
scanner.close();
}
}
}
按 Ctrl+S
保存文件。
编译更新后的程序:
javac UserInputDemo.java
java UserInputDemo
twenty-five
。程序现在不会崩溃,而是显示:Please enter your age: twenty-five
Error: Please enter a valid numeric age.
我们当前的实现虽然处理了异常,但会立即退出。让我们改进它,给用户多次输入有效年龄的机会:
在 WebIDE 中打开 UserInputDemo.java
文件。
修改代码以允许多次尝试:
import java.util.Scanner;
import java.util.InputMismatchException;
public class UserInputDemo {
public static void main(String[] args) {
// Create a Scanner object to read input
Scanner scanner = new Scanner(System.in);
boolean validInput = false;
int age = 0;
// Keep trying until valid input is received
while (!validInput) {
try {
// Prompt the user for their age
System.out.print("Please enter your age: ");
// Read the input
age = scanner.nextInt();
// If we get here, the input was valid
validInput = true;
} catch (InputMismatchException e) {
// Handle the exception if non-numeric input is provided
System.out.println("Error: Please enter a valid numeric age.");
// Clear the invalid input from the scanner
scanner.nextLine();
}
}
// Display the entered age
System.out.println("You entered: " + age);
// Close the scanner
scanner.close();
}
}
保存文件。
再次编译并运行程序:
javac UserInputDemo.java
java UserInputDemo
Please enter your age: twenty-five
Error: Please enter a valid numeric age.
Please enter your age: 25
You entered: 25
现在,我们的程序给了用户多次输入有效数据的机会。这是在优雅处理无效输入方面的一个重大改进。
除了异常处理,我们还可以使用条件语句来验证用户输入。这种方法使我们能够在处理输入之前实现自定义的验证规则。
输入验证是在处理用户输入之前检查其是否满足特定标准的过程。例如,我们可能希望确保年龄值不仅是一个数字,而且在合理的范围内。
让我们增强程序,以验证用户输入的年龄是否在 0 到 120 之间:
在 WebIDE 中打开 UserInputDemo.java
文件。
修改代码以包含范围验证:
import java.util.Scanner;
import java.util.InputMismatchException;
public class UserInputDemo {
public static void main(String[] args) {
// Create a Scanner object to read input
Scanner scanner = new Scanner(System.in);
boolean validInput = false;
int age = 0;
// Keep trying until valid input is received
while (!validInput) {
try {
// Prompt the user for their age
System.out.print("Please enter your age (0-120): ");
// Read the input
age = scanner.nextInt();
// Check if the age is within a valid range
if (age < 0 || age > 120) {
System.out.println("Error: Age must be between 0 and 120.");
} else {
// If we get here, the input was valid
validInput = true;
}
} catch (InputMismatchException e) {
// Handle the exception if non-numeric input is provided
System.out.println("Error: Please enter a valid numeric age.");
// Clear the invalid input from the scanner
scanner.nextLine();
}
}
// Display the entered age
System.out.println("You entered: " + age);
// Close the scanner
scanner.close();
}
}
按 Ctrl + S
保存文件。
编译程序:
javac UserInputDemo.java
java UserInputDemo
使用不同的输入测试程序:
25
):Please enter your age (0-120): 25
You entered: 25
Please enter your age (0-120): -5
Error: Age must be between 0 and 120.
Please enter your age (0-120):
Please enter your age (0-120): 150
Error: Age must be between 0 and 120.
Please enter your age (0-120):
Please enter your age (0-120): twenty-five
Error: Please enter a valid numeric age.
Please enter your age (0-120):
让我们创建一个更全面的示例,对用户注册表单的多个字段进行验证:
在 WebIDE 中创建一个名为 UserRegistration.java
的新文件。
在文件中添加以下代码:
import java.util.Scanner;
public class UserRegistration {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Get and validate username
String username = getValidUsername(scanner);
// Get and validate age
int age = getValidAge(scanner);
// Get and validate email
String email = getValidEmail(scanner);
// Display the registration information
System.out.println("\nRegistration Successful!");
System.out.println("Username: " + username);
System.out.println("Age: " + age);
System.out.println("Email: " + email);
scanner.close();
}
private static String getValidUsername(Scanner scanner) {
String username;
boolean validUsername = false;
do {
System.out.print("Enter username (3-15 characters): ");
username = scanner.nextLine().trim();
if (username.length() < 3 || username.length() > 15) {
System.out.println("Error: Username must be between 3 and 15 characters.");
} else {
validUsername = true;
}
} while (!validUsername);
return username;
}
private static int getValidAge(Scanner scanner) {
int age = 0;
boolean validAge = false;
while (!validAge) {
try {
System.out.print("Enter your age (0-120): ");
age = Integer.parseInt(scanner.nextLine());
if (age < 0 || age > 120) {
System.out.println("Error: Age must be between 0 and 120.");
} else {
validAge = true;
}
} catch (NumberFormatException e) {
System.out.println("Error: Please enter a valid numeric age.");
}
}
return age;
}
private static String getValidEmail(Scanner scanner) {
String email;
boolean validEmail = false;
do {
System.out.print("Enter your email: ");
email = scanner.nextLine().trim();
// Simple email validation: must contain @ and a period after @
if (!email.contains("@") || email.indexOf('.', email.indexOf('@')) == -1) {
System.out.println("Error: Please enter a valid email address.");
} else {
validEmail = true;
}
} while (!validEmail);
return email;
}
}
按 Ctrl + S
保存文件。
编译程序:
javac UserRegistration.java
java UserRegistration
示例有效输入序列:
Enter username (3-15 characters): johnsmith
Enter your age (0-120): 30
Enter your email: [email protected]
Registration Successful!
Username: johnsmith
Age: 30
Email: [email protected]
这个更全面的示例展示了如何同时使用异常处理和条件验证来验证不同类型的用户输入。
正则表达式(regex)为验证复杂的输入模式(如电子邮件地址、电话号码和密码)提供了强大的方法。在这一步中,我们将学习如何在 Java 中使用正则表达式来执行高级输入验证。
正则表达式是定义搜索模式的字符序列。这些模式可用于验证字符串是否符合特定格式。Java 提供了 java.util.regex
包,其中包含用于处理正则表达式的 Pattern
和 Matcher
类。
让我们增强 UserRegistration
程序,使用正则表达式进行更强大的输入验证:
在 WebIDE 中打开 UserRegistration.java
文件。
修改文件以包含正则表达式验证:
import java.util.Scanner;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class UserRegistration {
// Regular expression patterns
private static final String USERNAME_PATTERN = "^[a-zA-Z0-9_]{3,15}$";
private static final String EMAIL_PATTERN = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
private static final String PHONE_PATTERN = "^\\d{3}-\\d{3}-\\d{4}$";
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Get and validate username
String username = getValidUsername(scanner);
// Get and validate age
int age = getValidAge(scanner);
// Get and validate email
String email = getValidEmail(scanner);
// Get and validate phone number
String phone = getValidPhone(scanner);
// Display the registration information
System.out.println("\nRegistration Successful!");
System.out.println("Username: " + username);
System.out.println("Age: " + age);
System.out.println("Email: " + email);
System.out.println("Phone: " + phone);
scanner.close();
}
private static String getValidUsername(Scanner scanner) {
String username;
boolean validUsername = false;
Pattern pattern = Pattern.compile(USERNAME_PATTERN);
do {
System.out.print("Enter username (3-15 alphanumeric characters or underscore): ");
username = scanner.nextLine().trim();
Matcher matcher = pattern.matcher(username);
if (!matcher.matches()) {
System.out.println("Error: Username must be 3-15 characters long and contain only letters, numbers, or underscores.");
} else {
validUsername = true;
}
} while (!validUsername);
return username;
}
private static int getValidAge(Scanner scanner) {
int age = 0;
boolean validAge = false;
while (!validAge) {
try {
System.out.print("Enter your age (0-120): ");
age = Integer.parseInt(scanner.nextLine());
if (age < 0 || age > 120) {
System.out.println("Error: Age must be between 0 and 120.");
} else {
validAge = true;
}
} catch (NumberFormatException e) {
System.out.println("Error: Please enter a valid numeric age.");
}
}
return age;
}
private static String getValidEmail(Scanner scanner) {
String email;
boolean validEmail = false;
Pattern pattern = Pattern.compile(EMAIL_PATTERN);
do {
System.out.print("Enter your email: ");
email = scanner.nextLine().trim();
Matcher matcher = pattern.matcher(email);
if (!matcher.matches()) {
System.out.println("Error: Please enter a valid email address.");
} else {
validEmail = true;
}
} while (!validEmail);
return email;
}
private static String getValidPhone(Scanner scanner) {
String phone;
boolean validPhone = false;
Pattern pattern = Pattern.compile(PHONE_PATTERN);
do {
System.out.print("Enter your phone number (format: 123-456-7890): ");
phone = scanner.nextLine().trim();
Matcher matcher = pattern.matcher(phone);
if (!matcher.matches()) {
System.out.println("Error: Please enter a valid phone number in the format 123-456-7890.");
} else {
validPhone = true;
}
} while (!validPhone);
return phone;
}
}
按 Ctrl+S
保存文件。
编译程序:
javac UserRegistration.java
java UserRegistration
使用不同的输入测试程序:
Enter username (3-15 alphanumeric characters or underscore): a$
Error: Username must be 3-15 characters long and contain only letters, numbers, or underscores.
Enter username (3-15 alphanumeric characters or underscore):
Enter username (3-15 alphanumeric characters or underscore): johndoe
Enter your age (0-120): 25
Enter your email: johndoe.com
Error: Please enter a valid email address.
Enter your email:
Enter username (3-15 alphanumeric characters or underscore): johndoe
Enter your age (0-120): 25
Enter your email: [email protected]
Enter your phone number (format: 123-456-7890): 1234567890
Error: Please enter a valid phone number in the format 123-456-7890.
Enter your phone number (format: 123-456-7890):
Enter username (3-15 alphanumeric characters or underscore): johndoe
Enter your age (0-120): 25
Enter your email: [email protected]
Enter your phone number (format: 123-456-7890): 123-456-7890
Registration Successful!
Username: johndoe
Age: 25
Email: [email protected]
Phone: 123-456-7890
让我们来分析一下程序中使用的正则表达式模式:
USERNAME_PATTERN
: ^[a-zA-Z0-9_]{3,15}$
^
和 $
确保模式匹配整个字符串[a-zA-Z0-9_]
匹配任何字母(大写或小写)、数字或下划线{3,15}
指定长度应在 3 到 15 个字符之间EMAIL_PATTERN
: ^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$
PHONE_PATTERN
: ^\\d{3}-\\d{3}-\\d{4}$
\\d
匹配任何数字(0 - 9){3}
和 {4}
指定数字的个数-
匹配字面连字符正则表达式是进行输入验证的强大工具,但它们可能很复杂。随着你对它们越来越熟悉,你可以为你的应用程序创建更复杂的验证模式。
在这最后一步中,我们将构建一个完整的表单验证系统,该系统将整合我们所学的所有技术。我们将创建一个更具模块化、可复用的验证系统,以便能轻松地为不同应用程序进行扩展。
让我们先创建一个封装验证方法的工具类:
在 WebIDE 中创建一个名为 InputValidator.java
的新文件。
在文件中添加以下代码:
import java.util.regex.Pattern;
import java.util.regex.Matcher;
/**
* Utility class for validating user input
*/
public class InputValidator {
// Regular expression patterns
private static final String USERNAME_PATTERN = "^[a-zA-Z0-9_]{3,15}$";
private static final String EMAIL_PATTERN = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$";
private static final String PHONE_PATTERN = "^\\d{3}-\\d{3}-\\d{4}$";
private static final String PASSWORD_PATTERN = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\\S+$).{8,}$";
/**
* Validates a username
* @param username The username to validate
* @return true if the username is valid, false otherwise
*/
public static boolean isValidUsername(String username) {
if (username == null) {
return false;
}
Pattern pattern = Pattern.compile(USERNAME_PATTERN);
Matcher matcher = pattern.matcher(username);
return matcher.matches();
}
/**
* Validates an email address
* @param email The email to validate
* @return true if the email is valid, false otherwise
*/
public static boolean isValidEmail(String email) {
if (email == null) {
return false;
}
Pattern pattern = Pattern.compile(EMAIL_PATTERN);
Matcher matcher = pattern.matcher(email);
return matcher.matches();
}
/**
* Validates a phone number
* @param phone The phone number to validate
* @return true if the phone number is valid, false otherwise
*/
public static boolean isValidPhone(String phone) {
if (phone == null) {
return false;
}
Pattern pattern = Pattern.compile(PHONE_PATTERN);
Matcher matcher = pattern.matcher(phone);
return matcher.matches();
}
/**
* Validates an age
* @param age The age to validate
* @return true if the age is valid, false otherwise
*/
public static boolean isValidAge(int age) {
return age >= 0 && age <= 120;
}
/**
* Validates a password
* @param password The password to validate
* @return true if the password is valid, false otherwise
*/
public static boolean isValidPassword(String password) {
if (password == null) {
return false;
}
Pattern pattern = Pattern.compile(PASSWORD_PATTERN);
Matcher matcher = pattern.matcher(password);
return matcher.matches();
}
/**
* Gets the error message for an invalid username
* @return The error message
*/
public static String getUsernameErrorMessage() {
return "Username must be 3-15 characters long and contain only letters, numbers, or underscores.";
}
/**
* Gets the error message for an invalid email
* @return The error message
*/
public static String getEmailErrorMessage() {
return "Please enter a valid email address.";
}
/**
* Gets the error message for an invalid phone number
* @return The error message
*/
public static String getPhoneErrorMessage() {
return "Please enter a valid phone number in the format 123-456-7890.";
}
/**
* Gets the error message for an invalid age
* @return The error message
*/
public static String getAgeErrorMessage() {
return "Age must be between 0 and 120.";
}
/**
* Gets the error message for an invalid password
* @return The error message
*/
public static String getPasswordErrorMessage() {
return "Password must be at least 8 characters long and contain at least one digit, one lowercase letter, one uppercase letter, one special character, and no whitespace.";
}
}
Ctrl+S
保存文件。现在,让我们创建一个使用 InputValidator
类的新版注册表单:
在 WebIDE 中创建一个名为 CompleteRegistrationForm.java
的新文件。
在文件中添加以下代码:
import java.util.Scanner;
public class CompleteRegistrationForm {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Collect and validate user information
String username = getValidInput(scanner, "Username", InputValidator::isValidUsername, InputValidator.getUsernameErrorMessage());
int age = getValidAge(scanner);
String email = getValidInput(scanner, "Email", InputValidator::isValidEmail, InputValidator.getEmailErrorMessage());
String phone = getValidInput(scanner, "Phone number (format: 123-456-7890)", InputValidator::isValidPhone, InputValidator.getPhoneErrorMessage());
String password = getValidInput(scanner, "Password", InputValidator::isValidPassword, InputValidator.getPasswordErrorMessage());
// Display the registration information
System.out.println("\nRegistration Successful!");
System.out.println("Username: " + username);
System.out.println("Age: " + age);
System.out.println("Email: " + email);
System.out.println("Phone: " + phone);
System.out.println("Password: " + maskPassword(password));
scanner.close();
}
/**
* Generic method to get valid input from the user
* @param scanner The scanner to read input
* @param fieldName The name of the field being validated
* @param validator The validation function
* @param errorMessage The error message to display
* @return The validated input
*/
private static String getValidInput(Scanner scanner, String fieldName, java.util.function.Predicate<String> validator, String errorMessage) {
String input;
boolean validInput = false;
do {
System.out.print("Enter your " + fieldName + ": ");
input = scanner.nextLine().trim();
if (!validator.test(input)) {
System.out.println("Error: " + errorMessage);
} else {
validInput = true;
}
} while (!validInput);
return input;
}
/**
* Gets a valid age from the user
* @param scanner The scanner to read input
* @return The validated age
*/
private static int getValidAge(Scanner scanner) {
int age = 0;
boolean validAge = false;
while (!validAge) {
try {
System.out.print("Enter your age (0-120): ");
age = Integer.parseInt(scanner.nextLine());
if (!InputValidator.isValidAge(age)) {
System.out.println("Error: " + InputValidator.getAgeErrorMessage());
} else {
validAge = true;
}
} catch (NumberFormatException e) {
System.out.println("Error: Please enter a valid numeric age.");
}
}
return age;
}
/**
* Masks a password for display
* @param password The password to mask
* @return The masked password
*/
private static String maskPassword(String password) {
if (password == null || password.isEmpty()) {
return "";
}
return "*".repeat(password.length());
}
}
按 Ctrl+S
保存文件。
编译这两个 Java 文件:
javac InputValidator.java
javac CompleteRegistrationForm.java
java CompleteRegistrationForm
InputValidator
类中定义的规则验证每个输入。示例交互:
Enter your Username: john_doe
Enter your age (0-120): 35
Enter your Email: [email protected]
Enter your Phone number (format: 123-456-7890): 123-456-7890
Enter your Password: weakpw
Error: Password must be at least 8 characters long and contain at least one digit, one lowercase letter, one uppercase letter, one special character, and no whitespace.
Enter your Password: P@ssw0rd123
Registration Successful!
Username: john_doe
Age: 35
Email: [email protected]
Phone: 123-456-7890
Password: ***********
我们在这个最终示例中采用的方法有几个优点:
InputValidator
类中添加新的验证规则。getValidInput
方法是通用的,可用于不同类型的输入。这种设计遵循了良好的软件工程原则,能轻松地为不同应用程序调整验证系统。
在这个实验中,你学习了如何在 Java 程序中有效处理无效的用户输入。你已经从对输入处理的基本理解,逐步过渡到实现一个全面的验证系统。以下是你所完成内容的总结:
Scanner
类创建了一个收集用户输入的基本 Java 程序这些技术对于开发能够处理用户输入不可预测性的健壮 Java 应用程序至关重要。通过正确验证和处理无效输入,你可以防止程序崩溃、维护数据完整性并提供更好的用户体验。
在你继续 Java 编程之旅时,请记住,输入验证不仅是为了防止错误,也是为了增强安全性和可用性。你在这个实验中学到的原则可以应用于各种类型的应用程序,从简单的控制台程序到复杂的 Web 应用程序。