I have a setter which I want it to check if an email address contains the characters "#" and "." , before setting the value. If the email address does not contain these characters I want the user to enter the email address again. Should I read the new value inside the setter or is it bad pracice and should only be done in main or in a different method?
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();
}
}
}
No, this is bad practice.
The problem is that you will get stuck if you call the method in a context where you don't have an interactive console, e.g. in a unit test.
Throw an IllegalArgumentException, and let the caller implement the retry (or not).
In your setter:
void setEmail(String email) {
if (!email.contains("#") || !email.contains(".")) {
throw new IllegalArgumentException("Invalid email: " + email);
}
this.emailAddress = email;
}
In your caller:
while (true) {
try {
setEmail(emailAddress);
break;
} catch (IllegalArgumentException e) {
// Show a message, or whatever.
}
You are mixing functionality and responsibilities here in a bad way.
Yes, the setter should absolutely validate input, this is one of the most common reasons to utilize an accessor method instead of exposing the variable itself.
No, the setter should not make use of System.in or System.out to request new input from the user. Leave that up to main or what have you. This is outside of the scope of the setter's (and Person class' responsibilities)
The best methodology here is to use the IllegalArgumentException and let the calling code handle that as it wishes.
public void setEmail(String email)
{
if(email.indexOf('#')<0 || email.indexOf('.')<0)
{
throw new IllegalArgumentException("Invalid email address.");
}
this.email = email;
}
Your client code could then utilize it like so
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
}
}
In general it's a bad idea if a method does anything other than its name suggests.
If the method is called setFoo(), people expect it to update the field called foo and do nothing else. Of course you can (indeed you should) validate your input and throw an IllegalArgumentException if it isn't what you want, but nothing else.
This is often called "the principle of least surprise" and it's a very useful design principle for writing code.
Another general rule of thumb is that as much as possible, methods should be only responsible for one thing.
Of course what's a "thing" will vary, it could be something very specific (for example: "this method multiplies the two parameters") or it could be more general ("this method handles all my input"), but if you can't explain in a simple sentence what the method does, it probably does too much.
(As an exercise, think about how you'd explain to a friend what setEmail() does. Say the words out loud. It really works.)
This is even more important when you're doing I/O, like you do in your example: it should be very-very clear who reads from the Scanner and when, otherwise it becomes practically impossible to follow what input is expected at what stage of the program. In this case even your Person class shouldn't do anything with the Scanner. Handle the input somewhere else and leave the Person class to just represent a person.
Related
I have the next doubt. According to good practices of java, how to manage the cases in which the object can not be found and we want to know why.
For example, if someone has problems logging in our system and we want to inform them exactly what is the problem, we cannot return null because we lose the reason for not being able to log in. For example:
public User login(String username, String password) {
boolean usernameEmpty = (credentials.getUsername()==null || credentials.getUsername().isEmpty());
boolean passwordEmpty = (credentials.getPassword()==null || credentials.getPassword().isEmpty());
//getUserPassword return null if doesn't exist an user with username and password return null
User user = getUserPassword(username,password);
if (!usernameEmpty && !passwordEmpty && user!=null) {
LOGGER.info("Found " + username);
} else if (!usernameEmpty && !passwordEmpty && user==null) {
LOGGER.info("There is no such username and password: " + username);
} else if (usernameEmpty) {
LOGGER.info("Username can not be empty ");
} else if (passwordEmpty) {
LOGGER.info("Password can not be empty ");
}
return user;
}
I can think of two options with pros and cons to resolve it.
The first one consists in using Exceptions but I think that is not a good idea use different scenarios than expected like exceptions. For that reason, I discard it.
The second one is involve the object (User) in another object to manage the differents posibilities. For example, use something like this:
public class EntityObject<t> {
//Is used to return the entity or entities if everything was fine
private t entity;
//Is used to inform of any checked exception
private String exceptionMessage;
//getters / setters / ..
}
public EntityObject<User> login(String username, String password) {
boolean usernameEmpty = (credentials.getUsername()==null || credentials.getUsername().isEmpty());
boolean passwordEmpty = (credentials.getPassword()==null || credentials.getPassword().isEmpty());
User user = getUserPassword(username,password);
EntityObject<User> entity = null;
if (!usernameEmpty && !passwordEmpty && user!=null) {
LOGGER.info("Found " + username);
entity = new EntityObject<User>(user);
} else if (!usernameEmpty && !passwordEmpty && user==null) {
entity = new EntityObject<User>("There is no such username and password: " + username);
} else if (usernameEmpty) {
entity = new EntityObject<User>("Username can not be empty ");
} else if (passwordEmpty) {
entity = new EntityObject<User>("Password can not be empty ");
}
return entity;
}
I like more this second option than the first one but i don't like that i have to change the method signature to return a different class (EntityObject) than the usual (User).
What is the usual? How is it usually managed?
many thanks
An exception should be used when there is something exceptional happening in the system. For a normal flow and something that is expected to happen you should avoid using exceptions.
Following the good SOLID principals your method should do just one thing. So if it is a method to find user by username and password I would say the best would be to return null (or empty optional if using optionals). The reason is not lost. Actually it is pretty clear - there is not such user found with the supplied username and password (this reason includes the problem with empty username and it's the user of the method's fault to supply empty username to a login method). Adding complex logic to the method and additional entities for such things will make your code harder to maintain and to understand. This method's job is not to handle validation anyway.
If that class is used by a website or its some kind of API then they can handle the validation (if username or password is empty).
For me, second options look better. Probably, to know what was the error instead of writing messages in java code, you can create enum with possible scenarios and resolve it in the Front-end code, if you really need a message, you can create constructor inside enum to store it. It will simplify support and work with an object in the future. Plus, adding more scenarios will not hurt you much.
Basic version:
public class EntityObject<t> {
//Is used to return the entity or entities if everything was fine
private t entity;
//Is used to inform of any checked exception
private enum auth {
NO_PASSWORD, NO_USERNAME, USER_DOES_NOT_EXIST, SUCCESS
}
}
Version with enum constructor:
public class EntityObject<t> {
//Is used to return the entity or entities if everything was fine
private t entity;
//Is used to inform of any checked exception
private enum auth {
NO_PASSWORD("Password cannot be empty"),
NO_USERNAME("Username cannot be empty"),
USER_OR_PASSWORD_DOES_NOT_EXIST("No such username or password exist"),
SUCCESS("OK");
public String message;
public auth(String message) {
this.message = message;
}
}
}
I would say that the second approach is pretty fine. If I were you I would do that.
If you really don't want to change the return value, you can add another method that checks if a user can log in:
public static final String SUCCESS = "Success"
public String checkLoginError(String username, String password) {
// do all the checks and return the error message
// return SUCCESS if no error
}
Now the login method can then be one line:
return getUserPassword(username,password);
And you can use it like this:
String loginResult = checkLoginError(...);
if (loginResult.equals(SUCCESS)) {
User loggedInUser = login(...)
} else {
// do stuff with the error message stored in loginResult
}
It seems like your problem is stemming from a method which is responsible for multiple concerns.
I'd argue that the login method shouldn't be checking whether these values are blank. There is presumably some kind of UI (graphical or not) which is taking a username and password - this should be the layer performing validation on the user input.
The login method should only be concerned with whether the given credentials match a user in your system or not. There's only two outcomes - yes or no. For this purpose, you can use Optional<User>. It should tolerate the strings being empty as this will never match a user anyway (presumably it's impossible for a user to exist in such a state).
Here's some pseudo-code:
void loginButtonPressed()
{
if (usernameTextBox.text().isEmpty())
{
errorPanel.add("Username cannot be blank");
}
else if (passwordTextBox.text().isEmpty())
{
errorPanel.add("Password cannot be blank");
}
else
{
login(usernameTextBox.text(), passwordTextBox.text());
// assign above result to a local variable and do something...
}
}
public Optional<User> login(String username, String password)
{
Optional<User> user = Optional.ofNullable(getUserPassword(username, password));
user.ifPresentOrElse(
user -> LOGGER.info("Found " + username),
() -> LOGGER.info("Not found")
);
return user;
}
Java's null values are one of the worst aspects of the language, as you cannot really tell if a method is receiving a null value until it happens. If you are using an IDE (I hope so) you can check if it can control whether you are passing a null value where there shouldn't be one (IntelliJ can do this by adding the #NotNull annotation to the method's parameters).
Since it can be dangerous, it is better to avoid passing nulls around, as it will certainly lead to an error as soon as your code gets a bit complex.
Also, I think it would be reasonable to check for null values only if there is a concrete chance that there could be one.
If you want to express that a value can be present or not, it's better to use Optional<T>. If, for some reason, a null value could be passed instead of a real value, you could create an utility method whose only concern is to verify that the parameters are correct:
public Optional<EntityObject<User>> login(String username, String password) {
//isNotNull shouldn't be necessary unless you can't validate your parameters
//before passing them to the method.
//If you can, it's not necessary to return an Optional
if (isNotNull(username, password)) {
//Since I don't know if a password must always be present or not
//I'm assuming that getUserPassword returns an Optional
return Optional.of(new EntityObject<User>(getUserPassword(username,password).orElse(AN_EMPTY_USER)));
} else {
return Optional.Empty();
}
}
Anyway, I think that validating the input shouldn't be a concern of the login method, even if you don't want to use Optional; it should be done in another method instead.
Working on an android app which gathers data from the Open Weather API as a JSON. However the JSON does not always contain the same keys (ie. sometimes cloud data or a weather description is included, sometimes it isn't).
Right now my code looks like (with some extra getters/setters I didn't include here):
public class WeatherDescrip {
private String weather;
private String weather_Desc;
private String icon;
public WeatherDescrip(JSONObject weatherObj) {
try {
weather = weatherObj.getString("main");
} catch (JSONException e) {
weather = null;
e.printStackTrace();
}
try {
weather_Desc = weatherObj.getString("description");
} catch (JSONException e) {
weather_Desc = null;
e.printStackTrace();
}
try {
icon = weatherObj.getString("icon");
} catch (JSONException e) {
icon = null;
e.printStackTrace();
}
}
}
Basically if the JSON I get from the API call doesn't have the necessary key I let the program throw an exception, which will usually happen with at least one piece of data each time the app is run (there is more done like this).
If anyone could please let me know whether this is an acceptable way to code, and possibly how to better implement this I would much appreciate it.
If you haven't noticed I'm also a total noob, sorry in advance if this is a terrible way of doing this.
Many Thanks
This is generally not the correct forum for asking opinions, as you're asking for subjective opinions, there's technically no way to gauge a 'correct' answer, although you're free to select whatever answer you choose, if any ;-)
But in the nature of good will, I'll give you a few of my opinions.
Firstly, Exceptions are for just that, exceptions. If you have a scenario where you are in control of the code, and are aware of a potential for something not to occur in an 'ideal' way (e.g. like this, you're receiving dodgy data), then code for it, i.e.
if (data.contains("somethingOfInterest")) {
consume(data);
} else {
getDataFromSomewhereElse();
}
Rather than throw an exception, and force your program to handle it somewhere else (or not). Here's some additional information on why it's not a good idea to use exceptions for control flow.
Also, and this is advice from personal experience; in most scenarios, it's a good idea to do as little as makes sense within an Object's constructor, as it's more ugly to recover if exceptions do occur inside a constructor's method body. Instead, it may be better to encapsulate the logic you have there in some other factory-esque class or method, passing only the gathered data to the constructor. Something like:
public class WeatherDescrip {
private String weather;
private String weather_Desc;
private String icon;
public WeatherDescrip(String weather, String weather_Desc, String icon) {
this.weather = weather;
this.weather_Desc = weather_Desc;
this.icon = icon;
}
}
...
public static WeatherDescrip createWeatherDescrip(JSONObject weatherObj) {
if (!weatherObj.containsKey("main")
|| !weatherObj.containsKey("description")
|| !weatherObj.containsKey("icon")) {
throw SomeNewMeaningfulException("That I understand and can explicitly handle");
or....
return getMyDataFromSomeWhereElse();
}
return new WeatherDescrip(
weatherObj.getString("main"),
weatherObj.getString("description"),
weatherObj.getString("icon")
);
}
I hope this helps.
It's acceptable to throw exceptions whenever you decide. You just need to play how you want to handle it.
Is it acceptable to crash the program and boot your user back to the home screen? Absolutely not. Ever
Just read your data and handle the exceptions gracefully - no icon? Display a default. No data? Tell the user there is a problem right now so they aren't misled by the old data being displayed.
An alternate to avoid the majority of exceptions is to use GSON and Retrofit (I've linked a useful set of tutorials, not the home of GSON or Retrofit). With GSON you can create a model object, automatically map the data and then on your getters always return a value even if the JSON was incomplete
Example:
class MyObj {
#SerializedName("main")
private String weather;
public String getWeather() {
String weatherResult = weather;
if (weatherResult == null || "".equals(weatherResult) {
weatherResult = getString(R.strings.weather_unavailable);
}
return weatherResult;
}
}
Throwing an exception is usually reserved for when an error occurs, rather than having it it being an expected result of running your code, since there is overhead in throwing an exception which can make your program execute (slightly) slower.
Realistically, it can be used whenever you like, however you like, but I might instead suggest using has() to check if the key exists before trying to access it. It's a more efficient way of achieving the same result, without having to throw or catch an exception.
if(weatherObj.has('description')) {
weather_Desc = weatherObj.getString("description");
} else {
weather_Desc = null;
}
The value in the setter comes from a JTextFeild. I have try different method but it isn't working. I want to print out my custom error message. It isn't working for double, the String variable print the error message in the stacktrace.
This is the String method.
public void setInventoryname(String inventoryname) throws Exception {
if(inventoryname.isEmpty()){
throw new Exception ("Medicine name cannot be empty");
}
else{
this.inventoryname = inventoryname;
}
}
result of the string method.
java.lang.Exception: Medicine name cannot be empty
This is the double method
public void setInventorydesc(double inventorydesc) throws Exception {
if(!Double.toString(inventorydesc).isEmpty()){
throw new Exception("Set a number in Inventory qunatity");
}
else
{
this.inventoryqty = inventorydesc;
}
}
The result of double
java.lang.NumberFormatException: For input string: "dfasdf"
I want to receive the same result as of string for double.
Use Validator api and put your message.
Check org.apache.commons.validator
Double variable can never be empty, it can be zero.
You'll have to initialize the double variable, otherwise compiler will throw error.
If the zero value is what you mean by empty then you can compare that with zero to check.
You can not keep double variable uninitialized, it's all right with string but not with double.
Maybe you should step back and ask yourself for a second: does that really make sense?
What I mean is: you have two different methods, that take completely different arguments; and that have completely semantics; and still you are asking that both give you the same error message?
Lets have a closer look. First of all, throwing Exception objects is really bad practice. If you want to use a checked exception, then you better create your own subclass and use that. If you prefer unchecked exceptions, then you could throw IllegalArgumentException.
And just for the record: when you receive a double argument, that thing is always a number. Somebody already took the incoming string and made it a number. So your method is absolutely pointless. In other words: besides the things I told you, you should have a look into the code calling your methods.
Finally: read java language style guides. You should use camelCase for your variable and method names. And there is absolutely no need to abbreviate, call the thing inventoryQuantity; then everybody knows what it is! And you know, it is absolutely wrong that a method called setInventoryDesc changes the value of a field called inventoryQuantity. This might sound like nitpicking, but be assured: being precise and disciplined is one of the core practices in programming!
Pass inventorydesc as a string first - and then work with it ...
public void setInventorydesc(String inventorydesc) throws Exception {
if(inventorydesc==null ||inventorydesc.isEmpty()){
throw new Exception("Set a number in Inventory qunatity");
}
else
{
try{
this.inventoryqty = Double.parseDouble(inventorydesc);
}catch (NumberFormatException e){
throw new Exception("Inventory qunatity must be double");
}
}
}
If the number comes from a text field first you must parse it to get the double.
public static void setInventorydesc(String inventorydesc) throws Exception {
try{
double convertedInventorydesc = Double.parseDouble(inventorydesc);
this.inventoryqty = convertedInventorydesc;
}
catch (NumberFormatException ex){
throw new Exception("Set a number in Inventory quantity",ex);
}
}
try using this method
Double.isNan(double d)
Use this method to verify if the value is numeric or not.Or try to type cast the the string to double if it goes into catch block then display error message to user
I'm learning Java as well as studying books on code design.
I am wondering, is it possible in Java to have an if statement encapsulated in a method call that allows one to somehow exit the parent method if the boolean is false?
What I'm wondering is that if if I can further distill the following code
public void addStock (String stock) {
boolean stockNameIsValid = testStringForValidStockName(stock);
if (stockNameIsValid == false){
JOptionPane.showMessageDialog(getParent(), "Invalid text entered. Stock ticker names may only include upper-case alphabetical letters.", "Invalid Text Entry Error", JOptionPane.ERROR_MESSAGE);
return;
}
boolean stockAlreadyExistsInPanel = testForStockExistenceInListingPanel(stock);
if(stockAlreadyExistsInPanel == true){
JOptionPane.showMessageDialog(getParent(), "The same stock cannot be entered twice into the list of stocks being watched.", "Redundant Stock Error", JOptionPane.ERROR_MESSAGE);
return;
}
controller.addStockToDb(stock);
}
into something like
public void addStock(String stock){
giveErrorAndReturnIfStockNameInvalid(stock);
giveErrorAndReturnIfStockCannotBeFound(stock);
controller.addStockToDb(stock);
}
I'm wondering if doing this is possible because my IDE can't extract the code above any further, and having my code shaped in the second way above I think would communicate intent better and have a higher level of abstraction than the initial example.
I have this idea because I'm currently reading Uncle Bob's "Clean Code" book, and inside it says that methods ultimately should be as short as you can make them. If I encapsulate lower-level logic within method calls then it leaves the code reflecting higher-level logic. This makes the code easier to understand because it requires less of the developer's mental resources to get a general concept of what each part of the code does.
My goal here is to eliminate the reader from actually having to analyze the implementations details of the code here unless it's absolutely necessary. So instead of having to read through an entire method to comprehend it, the reader can instead get a more abstract representation of the logic of my code.
We have to use Exceptions, below pseudo code explains the same:
public void addStock(String stock){
try {
isStockNameValid(stock);
isStockExists(stock);
controller.addStockToDb(stock);
} catch(IllegalArgumentException exe) {
}
}
public boolean isStockNameValid(stock) throws IllegalArgumentException {
//check stock name is valid, if not
throw new IllegalArgumentException("Stock Name already exists");
}
public boolean isStockExists(stock) throws IllegalArgumentException {
//check stock exists, if not
throw new IllegalArgumentException("Stock Name already exists");
}
If parameter to addStock method is illegal, the methods could throw an illegal argument exception, for example:
public void giveErrorAndReturnIfStockNameInvalid(String stock)
{
// TODO: Check stock name
if(stock...)
{
throw new IllegalArgumentException("Stock has no valid name:"+stock);
}
}
notice this (IllegalArgumentException) is an unchecked exception, so you could get runtime exceptions uncaught if not handled in the calling method, another option could be to create a new domain specific exception like "InvalidStockException" and make it checked, so anyone using this method will be forced to add a try-catch block just in case something goes wrong and show the error message.
I am trying to find a simple method to check to see if a user's input meets a couple criteria for an email address. I've read through many threads on this subject and most seem to want to validate the email address too. I'm not trying to build some super duper email address validator/checker. I'm trying to build a method that checks for these things:
The string entered by the user contains the '#' sign.
There are at least two characters before the '#' sign.
There is a '.' after the at sign followed by only three characters. The domain name can be as long as needed, but the string must end with "._ _ _". As in ".com" or ".net"...
I understand that this is not an all encompassing email address checker. That's not what I want though. I want just something this simple. I know that this is probably a routine question but I can't figure it out even after reading all of the seriously crazy ways of validating an email address.
This is the code I have so far: (Don't worry I already know it's pretty pathetic.... )
public static void checkEmail()
{
validEmail(emailAddresses);
if(validEmail(emailAddresses))
{
}
}
public static boolean validEmail(String email) {
return email.matches("[A-Z0-9._%+-][A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{3}");
}
The javax.mail package provides a class just for this: InternetAddress. Use this constructor which allows you to enforce RFC822 compliance.
Not perfect, but gets the job done.
static boolean validEmail(String email) {
// editing to make requirements listed
// return email.matches("[A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{2,4}");
return email.matches("[A-Z0-9._%+-][A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{3}");
}
void checkEmails() {
for(String email : emailAddresses) {
if(validEmail(email)) {
// it's a good email - do something good with it
}
else {
// it's a bad email - do something... bad to it? sounds dirty...
}
}
}
int indexOfAt = email.indexOf('#');
// first check :
if (indexOfAt < 0) {
// error
}
// second check :
if (indexOfAt < 2) {
// error
}
// third check :
int indexOfLastDot = email.lastIndexOf('.');
if (indexOfLastDot < indexOfAt || indexOfLastDot != (email.length() - 4)) {
// error
}
Read http://download.oracle.com/javase/6/docs/api/java/lang/String.html for the documentation of the String methods.