我有一个setter,我希望它检查一个电子邮件地址是否包含字符" @"和"。" ,在设置值之前。如果电子邮件地址不包含这些字符,我希望用户再次输入电子邮件地址。我应该读取setter中的新值还是不好的实践,只能在main或不同的方法中完成?
import java.util.Scanner;
public class Person {
private String emailAddress;
Scanner input = new Scanner( System.in);
public void setEmail(String email)
{
while(email.indexOf('@')<0 || email.indexOf('.')<0)
{
System.out.println("The email address must contain the characters \"@\" and \".\" ");
System.out.println("Enter email address again:
email = input.nextLine();
}
}
}
答案 0 :(得分:6)
不,这是不好的做法。
问题是,如果您在没有交互式控制台的情况下调用该方法,则会卡住,例如:在单元测试中。
抛出IllegalArgumentException
,让调用者实现重试(或不重试)。
在你的二传手中:
void setEmail(String email) {
if (!email.contains("@") || !email.contains(".")) {
throw new IllegalArgumentException("Invalid email: " + email);
}
this.emailAddress = email;
}
在你的来电者中:
while (true) {
try {
setEmail(emailAddress);
break;
} catch (IllegalArgumentException e) {
// Show a message, or whatever.
}
答案 1 :(得分:3)
你在这里混淆了功能和责任。
是的,setter应该绝对验证输入,这是使用访问器方法而不是暴露变量本身的最常见原因之一。
不,设置者不应使用System.in
或System.out
来请求用户的新输入。把它留到main
或者你有什么。这超出了setter的范围(以及Person
类职责)
这里最好的方法是使用IllegalArgumentException
并让调用代码按照自己的意愿处理。
public void setEmail(String email)
{
if(email.indexOf('@')<0 || email.indexOf('.')<0)
{
throw new IllegalArgumentException("Invalid email address.");
}
this.email = email;
}
您的客户端代码可以像这样使用它
boolean goodEmail = false;
while (!goodEmail) {
String inputEmail = getTheEmailAddressFromTheUserSomehow();
try {
person.setEmail(inputEmail);
goodEmail = true;
} catch (IllegalArugmentException e) {
//try again!
//or don't, depends on the workflow of the application
}
}
答案 2 :(得分:2)
一般来说,如果某个方法做了名称以外的任何其他操作,那么这是一个坏主意。
如果该方法被称为setFoo()
,人们希望它更新名为foo
的字段,而不执行任何其他操作。当然,你可以(确实你应该)验证你的输入并抛出IllegalArgumentException
,如果它不是你想要的,但没有别的。
这通常被称为&#34; 最少惊喜的原则&#34;它是编写代码的一个非常有用的设计原则。
另一个一般的经验法则是,方法应尽可能只负责一件事。
当然是什么&#34;&#34;&#34;会有所不同,它可能是非常具体的(例如:&#34;此方法将两个参数相乘&#34;)或者它可能更通用(&#34;此方法处理我的所有输入&#34;),但如果你不能用一个简单的句子来解释这个方法的作用,它可能做得太多了。
(作为练习,请考虑一下你如何向朋友解释setEmail()
做了什么。大声说出这些话。它确实有用。)
当你进行I / O时,这更为重要,就像你在你的例子中所做的那样:从Scanner
读取的时间应该是非常清楚的,否则它几乎不可能遵循在该计划的哪个阶段预期的输入。在这种情况下,即使您的Person
课程也不应对Scanner
做任何事情。处理其他地方的输入并让Person
类只代表一个人。