Well, your program is not that bad and as far as I can tell there is only one problem and that is the you simply reversed the required test on the first and last groups. I would advise you to ensure the valid
is initialized to true
as the default. Then if none of the error codes are set, it will return true.
Presently you have the following:
if (lastfourdigits != firstfourdigits - 1) {
valid = false;
errorCode = 5;
}
But what you need is this
if (lastfourdigits != firstfourdigits + 1) {
valid = false;
errorCode = 5;
}
Your also have the following, unnecessary code.
String digits = ccNumber.replaceAll("[ˆ0-9]","");
The reason being is that you are simply using ccNumber
starting at the beginning for the first four characters and starting at the end for the last four. In this way you are not encountering dashes so you don't need to get just the digits.
Another recommendation is that as soon as you find an error you set the error code and return immediately. What's the use in continuing to process a card that has already been found to be flawed?
Other considerations and an alterative approach
It may not be a part of the assignment but I would also consider the following:
- What if you have more or less than 16 digits?
- What if you have more than three dashes giving more than four groups of numbers.
Checking the above would require additional logic and would complicate your effort. But it is something to consider. What follows demonstrates one way to check on those particular format issues and report them. This uses basic techniques and avoids streams so as not to repeat unnecessary operations.
This example throws selective errors based on problems found. Those may be changed or eliminated altogether as explained later. Credit card validation is a task where the most straightforward solution is best and should require low overhead.
First, declare a special exception to catch credit card errors.
class BadCreditCardException extends Exception {
public BadCreditCardException(String message) {
super(message);
}
}
Now declare some test data.
String[] testData = {
"1234-4566-9292-0210",
"1500-4009-2400-1600",
"1500-4009-2400-160000",
"1234-45669292-0210",
"1@34-45-66-9292-0210",
"1234-45B6-9292-0210",
"1234-4566-9292-2234",
"1234-4566-9292-021022",
"1234-4566-9292-0210",
"4567-4566-92!2-6835",
"1234-4566-9292-0210",
"1234-45+6-9292-0210",
"1234-4566-92x2-0210",
"1234-4566-9292-0210",
};
Test the credit cards and report errors. Note that only first encountered errors are reported. There may be multiple errors in the number.
String fmt = "%-23s - %s%n";
for(String card : testData) {
try {
validate(card);
System.out.printf(fmt,card, "Valid");
} catch (BadCreditCardException bce) {
System.out.printf(fmt,card, bce.getMessage());
}
}
The above prints.
1234-4566-9292-0210 - Invalid credit card checksum
1500-4009-2400-1600 - Valid
1500-4009-2400-160000 - Non group of 4 digits
1234-45669292-0210 - Insufficient or too may dashes
1@34-45-66-9292-0210 - Insufficient or too may dashes
1234-45B6-9292-0210 - Non digit found.
1234-4566-9292-2234 - Valid
1234-4566-9292-021022 - Non group of 4 digits
1234-4566-9292-0210 - Invalid credit card checksum
4567-4566-92!2-6835 - Non digit found.
1234-4566-9292-0210 - Invalid credit card checksum
1234-45+6-9292-0210 - Non digit found.
1234-4566-92x2-0210 - Non digit found.
1234-4566-9292-0210 - Invalid credit card checksum
The Explanation
The validate method. The method works as follows.
- split the card into groups using the dash
(-)
as a delimiter.
- If there are not four groups, throw an exception.
- Otherwise, sum each of the groups as follows each of these is checked during the summation process.
- first check that the group is of size four, if not throw an exception.
- as the group characters are iterated, if a non-digit is encountered, throw an exception.
- otherwise, continue computing the sum for the current group as follows:
- If the character is a digit, subtract
0
to convert it to an int
and add to the current sums array element.
- when completed, add that group sum to the
totalSum
of all digits.
- if the
totalSum
is divisible by four and the first group is one less than the last group, it is a valid card. Otherwise, throw an exception.
Alternative error handling modification
If the exceptions are not wanted, but just a pass or fail indication, then make the following changes.
- change the
void
return type to boolean
- if an exception was throw, simply return
false
- if all tests pass, then the last statement should return
true
public static void validate(String cardNumber) throws BadCreditCardException {
int [] groupSums = new int[4];
int totalSum = 0;
String [] groups = cardNumber.split("-");
if (groups.length != 4) {
throw new BadCreditCardException("Insufficient or too may dashes");
}
for (int i = 0; i < groupSums.length; i++) {
if (groups[i].length() != 4) {
throw new BadCreditCardException("Non group of 4 digits");
}
for(int digit : groups[i].toCharArray()) {
if (!Character.isDigit(digit)) {
throw new BadCreditCardException("Non digit found.");
}
groupSums[i]+= digit -'0';
}
totalSum += groupSums[i];
}
if (groupSums[0]+1 != groupSums[3] || totalSum % 4 != 0) {
throw new BadCreditCardException("Invalid credit card checksum");
}
}