i'm new to java programming and i'm trying to validate an email value using RegEx, the program should throw an exception when the user provides a wrong value, i managed to do this with an if-else. However, when i try to handle the error using a try-catch block the RegEx does not work anymore and the wrong value gets displayed anyways. How can i solve this?
here's the code
try {
String emailRegex = "^(.+)#(.+).(.+)$";
if(email.matches(emailRegex)) {
Pattern pattern = Pattern.compile(emailRegex);
System.out.println(pattern.matcher(email).matches());
} else {
throw new IllegalArgumentException();
}
} catch (IllegalArgumentException ex) {
System.out.println(ex.getLocalizedMessage());
}
This regular expression rejects valid email addresses. Even if you did fix it. For example, foo#bar is actually valid (top-level domains can contain MX records. A few do!). This is the general formula for 'is it valid email':
Does it contain spaces? If yes, reject.
Does it contain at least 1 #? If no, reject.
Is the last # at position 0 (i.e. at the start), or at the end? Reject.
Otherwise, pass. There are a few invalid emails that would nevertheless pass, but this is by and large no problem: foo#bar is not really legal, but the only real way to know that, is to send an email to it and request the user click a link inside it before they can continue. No regexp is ever going to figure out if the email address entered by a user is in fact a valid email address, let alone an email address that belongs to that user, hence, there is no real point in trying to go any further than that. You're attempting to catch honest typoes, not actually validate anything, because that is impossible. Note that it can easily become legal tomorrow - someone just needs to set up the bar top level domain and make sure there's an MX record for it in its DNS registration and voila. foo#bar is now legal.
Your regex is close to this ideal; you just want ^.+#.+$
NB: If you want to break spec and reject any email addresses to top-level domains, your regex is broken. Your intent is clearly to want foo#a.b, but you don't do that - that middle ., nestled between (.+), is still a regex dot operator, meaning: "any character". You'd want \\. for that instead. But, don't - as I said, TLDs are themselves rare as mail servers, but valid according to spec!
Fix this and your code 'works', but note that your code can go only one of two ways:
The regexp matches, in which case you again run the string through the regexp (seems rather pointless to do it twice!), and then trivially prints 'true'. The entire Pattern pattern = ...; System.out.println(...) might as well be System.out.println("true"); - that's what it will always do - yes, the regexp that just matched, is still going to match, of course.
The regexp does not match, in which case we get to the else block, which throws an exception. This then goes to the catch block which can only catch this (as nothing else throws IllegalArgumentEx here), and prints the 'localized message', which is null here.
So, this code prints true if it matches, and null if it does not. That seems.. weird. And is needlessly complicated if that's what you wanted.
Better:
class Test {
private static final Pattern EMAIL_PATTERN = Pattern.compile("^.+#.+$");
public static boolean isValidEmail(String email) {
return EMAIL_PATTERN.matcher(email).matches();
}
public static void main(String[] args) {
var keyboard = new Scanner(System.in);
while (true) {
System.out.print("Enter an email address: ");
String line = keyboard.nextLine().trim();
if (line.isEmpty()) System.exit(0);
if (isValidEmail(line)) {
System.out.println("Valid");
} else {
System.out.println("Not valid");
}
}
}
}
The try/catch block do not add anything useful here. You use try/catch when you want to transfer an error condition across method calls, not within the same method call, and not when the only meaningful data you can convey is a boolean flag. If that's all you have ('valid' or 'not valid'), almost always you just want a boolean.
If you really want the exception instead:
class Test {
private static final Pattern EMAIL_PATTERN = Pattern.compile("^.+#.+$");
public static void validateEmail(String email) throws IllegalArgumentException {
if (!EMAIL_PATTERN.matcher(email).matches()) {
throw new IllegalArgumentException("Email '" + email + "' is not valid");
}
}
public static void main(String[] args) {
var keyboard = new Scanner(System.in);
while (true) {
System.out.print("Enter an email address: ");
String line = keyboard.nextLine().trim();
if (line.isEmpty()) System.exit(0);
try {
validateEmail(line);
System.out.println("Valid");
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
}
}
}
Related
I have this code:
public static void main(String[] args) {
List<Valtozas> lista = new ArrayList<Valtozas>();
try {
File fajl = new File("c://data//uzemanyag.txt");
Scanner szkenner = new Scanner(fajl, "UTF8");
while (szkenner.hasNext()) {
String sor = szkenner.nextLine();
String [] darabok = sor.split(";");
String szoveg = darabok[0];
Valtozas valtozas = new Valtozas(Integer.valueOf(darabok[0]), Integer.valueOf(darabok[1]), Integer.valueOf(darabok[2]));
lista.add(valtozas);
}
}
catch (Exception e) {
}
//3.FELADAT
System.out.println("3.Feladat: Változások száma: "+lista.size());
}
}
Here I want to convert the String to int, but I cant. I tried the Integer.Valueof(darabok[0]), but its not working. And nothing is happening, so the code is build, but quit from the while.
Based on the source code you have shown us, the problem is that there is a format mismatch between the input file and the program you are trying to read.
The program reads the file a line at a time, and splits it into fields using a single semicolon (with no whitespace!) as the file separator. Then it tries to parse the first three fields of each split line as integers.
For this to work the following must be true:
Every line must have at least three fields. (Otherwise you will get a ArrayIndexOutOfBound exception.)
The three fields must match the following regex: -?[0-9]+ i.e. an optional minus signed followed by one or more decimal digits.
The resulting number must be between Integer.MIN_VALUE and Integer.MAX_VALUE.
Elaborating on the above:
Leading and trailing whitespace characters are not allowed.
Embedded decimals markers and grouping characters are not allowed.
Scientific notation is not allowed.
Numbers that are too large or too small are not allowed.
Note that if any of the above constraints is not met, then the runtime system will throw an exception. Unfortunately, you surround your code with this:
try {
...
}
catch (Exception e) {
}
That basically ignores all exceptions by catching them and doing nothing in the handler block. You are saying to Java "if anything goes wrong, don't tell me about it!". So, naturally, Java doesn't tell you what is going wrong.
DON'T EVER DO THIS. This is called exception squashing, and it is a really bad idea1.
There are two ways to address this:
Print or log the stacktrace; e.g.
catch (Exception e) {
e.printStackTrace();
}
Remove the try / catch, and add throws IOException to the signature of your main method.
(You can't just remove the try / catch because new Scanner(fajl, "UTF8") throws IOException. That's a checked exception so must be handled or declared in the method signature.)
Once you have dealt with the exception properly you will get an exception message and stacktrace that tells you what is actually going wrong. Read it, understand it, and fix your program.
1 - It is like taping over the "annoying" red light that indicates that your car's oil level is low!
I have to do a little program based in a shop, I have to add new clients to the shop customer collection, new items to the shop stock, edit them etc, so I use user input(scanner) to create this new objects. I have all the methods I need for this already without exceptions.
I would like some simple java exception handling for when the user introduces a string were he is supposed to enter a integer or viceversa.
For example if I'm executing a method to create a item for the shop and when I ask the user to introduce the stock(integer) the user types hello instead of a number the program crashes, I would like to handle the exception, show a error message, don't create the object and relaunch the item creation method from the beggining(or relaunch the submenu it was right before)
should I use try and catch? the method in try, when it fails catch throws message of error and relaunches the item creation menu? How should i do this? I've been searching and found a interesting method for integers here:
Exception Handling for no user input in Java
The problem is I don't know how I could handle possible exceptions for when introducing the ID for the user(which would be a string composed of 8 numbers and a letter like for example: 13234354A, so how could I show a error if a user introduces "sjadsjasdj" as a ID instead of something sort of realistic ) or some other things like handling exceptions for a few enum or boolean variables I use when creating this objects.
I've been looking in this site and searching google but I haven't found what I need or are more complex than what I understand with my little knowledge, also English is not my native language so my searches may be a little off.
Thanks for your time!
When you are reading the input just read in the the entire ID 123A for example and verify that each character is valid using for example Character.isDigit() and Character.isLetter(). With a 4 letter case
import java.util.Scanner;
public class Test {
public static void main(String[]args) {
boolean flag = false;
Scanner kb = new Scanner(System.in);
while(!flag) {
String id = kb.next();//To get the next word
flag = true;//by default its assumed to be valid input
if(id.length() == 4) {
for(int i = 0; i < 3; i++) {
if(!Character.isDigit(id.charAt(i))) {
flag = false;
}
}
if(!Character.isLetter(id.charAt(3))) {
flag = false;
}
}
else {
flag = false;
}
System.out.println("ID is "+ (flag == true?"Valid":"Invalid"));
}
}
}
Output
1234
ID is Invalid
123A
ID is Valid
You could throw your own error at the end if you want or just loop back to the beginning to take a new input.
I have a registration page where the user has to enter personal information about themselves, if something entered is invalid then error notifications should pop up
if (!PhoneNumber.startsWith("055") || !PhoneNumber.startsWith("050") || !PhoneNumber.startsWith("056") || !PhoneNumber.startsWith("052")) {
// does not match
contact_number.setError("Please enter a valid phone number");
return;
}
if (TextUtils.isEmpty(password) )
{
VendorRegPassword.setError("Please enter your password");
return;
}
else if (password.length() < 6)
{
VendorRegPassword.setError("Please use more than 6 characters");
return;
}
if (TextUtils.isEmpty(email) || !email.contains("#") )
{
VendorRegEmail.setError("Please enter a valid email address");
}
Independently they work on their own but when put together it does not work properly, also the phone number error does not work properly, can somebody help me with this?
The other answer is correct; the return statement simply prevents all checks to be executed. And in this case, you want all validations to take place, as each validation has a different way of informing the user about the problem.
Beyond that: from a "clean code" perspective you should be careful to simply stuff all validations into the same poor method. Instead: structure your code so that it clearly expresses what is going on, like:
private void validateAll(PhoneNumber number, Email email, Password password) {
validatePhoneNumber(number);
validateEmail(email);
...
and separate helpers like
private void validatePhoneNumber(number) {
boolean validPrefix = false;
for (String validPrefix : PREFEIXES) {
if (phoneNumber.startsWith(validPrefix) {
validPrefix = true;
}
}
if (!validPrefix) {
contact_number.setError("Please enter a valid phone number");
}
}
for example. And please note - I fixed another bad practice (your idea to simply hard-code all valid prefixes). You always want to put such information into some constant set/list; so that you have exactly one place in your code that knows what those prefixes are.
They are not working together properly because you are returning from the method in if or else ifconditions. Remove return statements from if and else. Because return will terminate the execution of method, so further code will never be executed due to return.
They are working separately because, there is no need to execute further conditions (no further conditions at all), so returning from method seems correct solution.
Language: Java, IDE: eclipse mars
The program is supposed to prompt the user (using JOptionPane) for a positive value. I'm trying to catch the invalid entries. My while statement catches the negative numbers but not the strings. When a negative number is entered, the prompt is shown again, but when a string value is entered, the exception is caught and the program moves on (when it should re prompt the user).
Once a positive value has been entered, the program assigns it to a value in another class. (We're learning the MVC OOP design pattern).
Double.isNaN(Double.parseDouble(h)) ---> can anyone help me find what am I missing?
// prompt to get bandwidth from user
// check for validity
// if invalid, prompt again
try{
h = JOptionPane.showInputDialog("Enter bandwidth as a positive number");
// loop until parsed string is a valid double
while (Double.isNaN(Double.parseDouble(h)) || Double.parseDouble(h) <=0) {
h = JOptionPane.showInputDialog("Enter bandwidth as a positive number");
}
// h has been set to valid double, set it to bandwidth
model.setBandwidth(Double.parseDouble(h));
}catch(NumberFormatException|NullPointerException NFE){
System.err.println("Caught exception: " + NFE.getMessage());
}
This is because of how parseDouble() works.
Throws:
NumberFormatException - if the string does not contain a parsable double.
(See here)
So if the String is not a double parseDouble() will not return NaN but throw an exception, which means your catch clause will be called.
To solve this problem maybe use recursively algorithm which will call your method again if an exception is thrown.
As 4castle already stated, you need to move your try/catch block inside your while loop.
However, for validating user input you can basically stick to the following pattern:
public Foo getUserInput() {
Foo result;
do {
try {
String s = requestUserInput(); // something like Scanner.nextLine()
result = parseUserInput(s); // something like Double.parseDouble(String)
}
catch(Exception exc) {
// maybe you want to tell the user what's happened here, too
continue;
}
}
while(!isValid(result)); // something like (0 < result)
return result;
}
Ok, I have this code that asks an input for a username and a password. I used JOptionPane. What I want with the program is to display an error message if the the input on the username field has a number, and goes back to the previous dialog box asking for the username again. I have this while loop yet it does not function the way it should. Please do help. The program does not show the error message on my catch method and neither does it loop for the dialog box to display.
public class SwingExercise {
public static void main(String[] args) {
String name = "";
String pw = "";
boolean input = true;
boolean hasDigit = false;
while (input) {
try {
while (name.equals("")) {
name = JOptionPane.showInputDialog(null, "Enter username:");
if (name.equals("")) {
JOptionPane.showMessageDialog(
null, "No input.", "Error", JOptionPane.ERROR_MESSAGE);
name = "";
}
while (hasDigit) {
for (int i = 0; i < name.length(); i++) {
if (Character.isDigit(name.charAt(i))) {
throw new InputMismatchException();
}
}
hasDigit = false;
}
}
input = false;
while (pw.equals("")) {
pw = JOptionPane.showInputDialog(null, "Enter password:");
if (pw.equals("")) {
JOptionPane.showMessageDialog(
null, "No input.", "Error", JOptionPane.ERROR_MESSAGE);
pw = "";
}
}
} catch (NullPointerException e) {
System.exit(0);
} catch (InputMismatchException e) {
JOptionPane.showMessageDialog(
null, "Invalid input.", "Error", JOptionPane.INFORMATION_MESSAGE);
}
}
}
Please do mention any comments regarding the other lines in my code and if there are any unnecessary lines. Thank you in advance :)
There seems to be absolutley no way to get into the while(hasDigit) loop because you have it set to false, and there is nothing setting it to true.
One problem is that the value of hasDigit will always remain false. You probably will want to define hasDigit as true initially.
boolean hasDigit = true;
Some comments on style, since you asked:
In general, you want your try() blocks to be as short as possible, so it's clear which lines you're expecting to throw an exception. Otherwise you may unexpectedly catch an exception from a line that you didn't think could generate it, and then handle it incorrectly. This means the code will probably be longer, but it's far more important that it be easier to maintain and debug.
When it's legitimate for a string to be null, it's common to write if ("".equals(name)) rather than if (name.equals("")). Since the hard-coded empty string can never be null, you needn't surround the code with a try/catch block.
There's no need to set name or pw to the empty string inside an if() that tests to see if they're empty.
You probably don't want to echo the password. See JOptionPane to get password.
The code explicitly forbids digits in the name but accepts every other character, including punctuation and special characters. It's generally good programming practice to use a whitelist of acceptable input, rather than a blacklist of forbidden input. That way you'll never be surprised by invalid data that's unexpectedly accepted.
The outermost while() loop will exit if the password is invalid, since input only depends on the name. Better to set input to false at the top of the loop, then set it to true if either input is invalid.
Since the name and pw blocks are almost identical (they prompt for a non-empty string), consider extracting them into a helper function. You'll want to pass parameters that specify the prompt and whether or not to echo the input back to the user.