Indeed using java Exception for common cause is considered a bad practice, and as @Michael said, Exceptions must be exceptional, because
- they break flow control
- they are slow (more details here How slow are Java exceptions?)
- they do not mix with functional paradigm (where Java is in part going to with the addition of lamda-expressions
However, creating a custom object for wrapping validation data is a good thing and InvalidEmailAddressException
can be turned into CheckedEmail
:
import java.util.List;
import java.util.stream.Collectors;
public class EmailValidator {
public List<CheckedEmail> validate(List<String> emailAddresses) {
return emailAddresses.stream().map(this::validate).collect(Collectors.toList());
}
public CheckedEmail validate(String emailAddress) {
String[] emailParts = emailAddress.toString().split( "@", 3 );
final boolean valid;
if ( emailParts.length != 2 ) {
valid = false;
} else {
// More validation can go here using one or more regex
valid = true;
}
return new CheckedEmail(emailAddress, valid);
}
public static final class CheckedEmail {
private final String emailAddress;
private final boolean valid;
private CheckedEmail(String emailAddress, boolean valid) {
this.emailAddress = emailAddress;
this.valid = valid;
}
public String getEmailAddress() {
return emailAddress;
}
public boolean isValid() {
return valid;
}
}
}
This in turn can be tested quite easily (and improved with a parameterized test):
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
public class EmailValidatorTest {
private final EmailValidator emailValidator = new EmailValidator();
@Test
public void invalid_email() {
EmailValidator.CheckedEmail checkedEmail = emailValidator.validate("missing.an.at.symbol");
assertThat(checkedEmail.isValid()).isFalse();
}
@Test
public void valid_email() {
EmailValidator.CheckedEmail checkedEmail = emailValidator.validate("at.symbol@present");
assertThat(checkedEmail.isValid()).isTrue();
}
@Test
public void multiple_email_addresses() {
List<String> emailAddresses = Arrays.asList("missing.an.at.symbol", "at.symbol@present");
List<EmailValidator.CheckedEmail> checkedEmails = emailValidator.validate(emailAddresses);
assertThat(checkedEmails)
.extracting(ce -> ce.getEmailAddress() + " " + ce.isValid())
.containsExactly(
"missing.an.at.symbol false",
"at.symbol@present true");
}
}
If somewhere the point is just to log this, then:
List<EmailValidator.CheckedEmail> checkedEmails = emailValidator.validate(emailAddresses);
checkedEmails.stream()
.filter(ce -> !ce.isValid())
.map(ce -> String.format("Email address [%s] is invalid", ce.getEmailAddress()))
.forEach(logger::error);
Hope this helps !