I have a method using throws, inside is two if/else statements, the if statement tests a condition and then throws an exception if it fails, the problem is of course is that if the first if/else block fails my second never gets executed, is there an alternative way to approach this problem?
EDIT (Further Information)
My code is checking whether a person object has the correct first name Test 1, or the correct surname Test 2, if not throw exception A or B, code further on then adds the person into a group if they pass both conditions
Method throws Exception A, Exception B
{
//Test First name
if(Test1)
{
If persons firstname is correct, Test1 is true
}
else
{
throw new Exception A
}
//Test Surname
if(Test2)
{
If persons surname is correct, Test2 is true
}
else
{
throw new Exception B
}
//If everything is fine, add the person to a list.
if (Test1 & Test2)
{
Add Person to a list
}
}
Based upon your description, I am thinking that you could change to
if(Test1)
{
if(!Test2)
{
throw new Exception B
}
// Do some work here
}
else
{
throw new Exception A
}
Another way to consider is by creating methods
bool test1 = correctFirstName (fname);
bool test2 = correctLastName (lname);
if (test1 && test2)
{
// do some stuff
}
else {
if (!test1) // throw ExceptionA
else // throw ExceptionB
}
Something like this should work. I would of course recommend not using generic Exception, but I would also not use two different types of exceptions as your original code implied.
Method throws Exception A, Exception B
{
String errMsg = "";
//Test First name
if(Test1)
{
If persons firstname is correct, Test1 is true
}
else
{
errMsg = "Invalid first name";
}
//Test Surname
if(Test2)
{
If persons surname is correct, Test2 is true
}
else
{
errMsg = "Invalid surname";
}
//If everything is fine, add the person to a list.
if (errMsg.equals(""));
{
Add Person to a list
}
else
{
throw new Exception(errMsg);
}
}
It appears the task is not possible, the instructions given to me did not state that in order to trigger one Exception or the other I had to comment out code.
Related
I have a method where I need to return a specific object if found, otherwise throw an exception. So I wrote the following:
public CustomerDetails findCustomer( String givenID ) throws CustomerNotFoundException{
for(CustomerDetails nextCustomer : customers){
if(givenID == nextCustomer.getCustomerID()){
return nextCustomer;
}else{
throw new CustomerNotFoundException();
}
}
}
But it requires me to add a return statement at the bottom of the method. Is there a way to ignore this?
It asks you to provide a valid outcome from the method for the case when the loop is not executed (i.e. customers is empty). You have to do this:
for (CustomerDetails nextCustomer : customers){
if (givenID == nextCustomer.getCustomerID()){
return nextCustomer;
}
}
throw new CustomerNotFoundException();
because otherwise you would throw the exception after the first element that doesn't meet the condition provided in the if.
Change your code to :
public CustomerDetails findCustomer( String givenID ) throws CustomerNotFoundException{
for(CustomerDetails nextCustomer : customers){
if(givenID == nextCustomer.getCustomerID()){
return nextCustomer;
}
}
throw new CustomerNotFoundException();
}
You can return the object if it is found. If it will be not found it throw an exception at end of the loop:
public CustomerDetails findCustomer( String givenID ) throws CustomerNotFoundException{
for(CustomerDetails nextCustomer : customers){
if(givenID.equals(nextCustomer.getCustomerID())){
return nextCustomer;
}
}
throw new CustomerNotFoundException();
}
Note. you compare strings with ==. Here you have to usethe equals method!
An exception should be thrown if an unexpected behavior occurs. A failed search is not an exception, but a rarely common cause.
For the reason of good design, you should not throw the exception. Instead you can expand your calling method to test the result for null-iness or similiar.
You can just add a return; at the end of your method. It won't be accessible so it won't cause issues.
You could also use a try catch around your loop. Here is a handy tutorial for that if you wish to follow this route.
http://tutorials.jenkov.com/java-exception-handling/basic-try-catch-finally.html
If the customer could not be found in the loop, it should throw exception out of the loop. Also you should use ".equals" instead of "==", because "givenID" is an object.
public CustomerDetails findCustomer( String givenID ) throws CustomerNotFoundException {
for (CustomerDetails nextCustomer : customers) {
if (givenID.equals(nextCustomer.getCustomerID())){
return nextCustomer;
}
}
throw new CustomerNotFoundException();
}
In my code:
if (id.isEmpty() || name.isEmpty()) {
warlbl.setText("Warning, Empty ID or Name Fields");
return;
}
id and name are String that give from JTextFields ,
Is necessary use return; in here or Not?
Yes, it can be:
if (...) {
...
return;
}
// nothing at this point will be reached if the if-statement is entered
vs.
if (...) {
...
}
// code here will still be reached!
return exits the current method you are "in".
Of yource it is not necessary but maybe you want to exit the method if id.isEmpty() and name.isEmpty(). So no and yes. It is not neccassary but you may want to return
You can use return to break out of a method, continue to skip a loop or a break to break out of a block.
Often there are 2 ways:
public void test() {
if (!statement) {
// to something if statement is false
} else {
//we failed, maybe print error
}
}
or:
public void test() {
if (statement) {
//we failed, maybe print error
return;
}
//do something if statment is false
}
But this is more a kind of "style". Mostly I prefere the second way, just because it's less spagetti :P
Keep in mind. If your return statement would be the last statment executed it's redundant.
Java reference:
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/branch.html
See the two examples below. Assume both classes contains public methods belonging to a widely used API library.
AClass.java is easier to write (maybe easier to read due to less noise), but when error is detected, the first method in stack trace is an internal method (nullCheck(...)) and the exception message is not referring to that method. Could this cause unnecessary confusion to the user? I mean in the sense of the user thinking: "it's an internal method which has thrown an exception, must be a bug in the library, not a fault in my program. What a ** useless library..."
BClass.java is more tiresome to write (with all its if statements), but when error is detected the first line of the stack trace pinpoints the API method (called by user) where error was first detected. Would this more likely make user think: "I'm calling that method from my code, must be something wrong with the parameter I'm passing in".
Which would be the preferred way of throwing exception when checking parameters for validity in a public API? Or are the two examples considered equal?
public class AClass {
public void publicApiMethod1(String a){
nullCheck(a, "a");
// do something...
}
public void publicApiMethod2(String a, String b, String c){
nullCheck(a, "a");
nullCheck(b, "b");
nullCheck(c, "c");
// do something...
}
private void nullCheck(Object a, String argName) {
if(a == null){
throw new NullPointerException("Null argument: " + argName);
}
}
}
public class BClass {
public void publicApiMethod1(String a){
if(a == null){
throw new NullPointerException("Null argument: 'a'");
}
// do something...
}
public void publicApiMethod2(String a, String b, String c){
if(a == null){
throw new NullPointerException("Null argument: 'a'");
}
if(b == null){
throw new NullPointerException("Null argument: 'b'");
}
if(c == null){
throw new NullPointerException("Null argument: 'c'");
}
// do something...
}
}
If your error message is descriptive (and it is), no one will bother to look at the stack trace. Thus the first form is better because it encapsulates the validation logic.
Note that there are plenty of assertion methods in various libraries ready to use, see: Objects.requireNonNull and Validate.notNull).
I would do it that way, basically based on your AClass:
public void publicApiMethod2(String a, String b, String c){
try {
nullCheck(a, "a");
nullCheck(b, "b");
nullCheck(c, "c");
}
// catch the NullPointerException,
// and any other Exception explicitly thrown by your validation methods
catch (NullPointerException e) {
throw new IllegalArgumentException(e.getMessage());
}
// do something...
}
That way, the user gets an explicit message and a stacktrace that points to the public method.
in your b class why dont you use
if( (c == null)|| (b == null)|| (a == null) ){
//thrown my red ball
}
less tiresome, more readable
I would think that Class A is fine, as long as you clearly document it with a #throws. I have seen plenty of libraries that will throw deeper in the stack. The important thing is for the user to understand WHY an error was thrown and what they can do to avoid it.
I have this recursive method:
public Hund getMor(int id) {
Hund barn = getHund(id);
int idMor = barn.getId_mor();
Hund mor = getHund(idMor);
return mor;
}
public String getMorTre(int id) {
if (id == 0) {
return null;
}
if (!existHund(id)) {
return "Hunden du søkte etter finnes ikke";
} else {
if (id == 0) {
return null;
} else {
Hund mor = getMor(id);
MinRamme.jta.append(mor.toString() + "\n");
int morId = mor.getId();
return getMorTre(morId);
}
}
}
I have tried to remove the nullpointer by returning null if the id is 0 but this does not work. Does anyone have a solution?
NPE:
Exception in thread "AWT-EventQueue -0" java.lang.nullpointerexception
at Arkiv.getMorTre(Arkiv.java:209)
at Arkiv.getMorTre(Arkiv.java:211)
at Arkiv.getMorTre(Arkiv.java:211)
at MinRamme$4.actionPerformed(MinRamme.java:89) <37 internal calls>
Where does the NullPointerException occur? That would help... That being said:
Inside your else clause, your
if (id==0) {
is useless, since you're testing that at the beginning and the id isn't changed.
I think you need to check if
getMother(id)
returns null, that is probably where you're getting the NullPointer... but you could confirm that now, couldn't you?
It is likely (but difficult to confirm until you let us know what line is throwing the NPE) that the line that generates the NPE is
MyFrame.jta.append(mother.toString() + "\n");
because mother is null. You could change your code into this:
Dog mother = getMother(id);
if (mother == null) {
//do something
}
There really isn't enough information here. What line are you getting the null pointer on?
if, as I suspect, it's here:
MyFrame.jta.append(mother.toString() + "\n");
Then you need to determine, through debugging, that it's definitely mother that is null. If you have done that, then you can be absolutely positive that your getMother(id); returns null, for the id that you are passing in.
If I were you I would create a unit test for the getMother(id) method and pass in the id that is causing the failure.
If you don't know what id value is causing the problem, then at the very least stick in some System.out.print() statement to find out what is going on. Although, you'd be better using some logging framework, such as log4j.
Hope this helps.
Its because your exception is at mother.toString() method..
try this
try
{
MyFrame.jta.append(mother.toString() + "\n");
}catch(NullPointerException ignore){}
I currently have 3 classes, a main class containing a GUI, in which i'm calling this method, a customer class containing the data, and a customerList class which gathers the data from the customer class, puts it into an array list, and also contains the search arraylist method.
I'm trying to implement a search method which can be called from my main class on an action event handler. I'm having a few problems though.
Whenever I run the method, the " System.out.println(customer.returnFamilyName());" line always displays the first familyname in my arraylist.
Don't hesitate to ask for more information, I'm not sure how well i've explained this.
Here is my method:
public void searchCustomer(String familyName) {
int index = 0;
boolean found = false;
customer customer;
while(index < CustomerList.size() && !found) {
customer = CustomerList.get(index);
if(customer.returnFamilyName().equalsIgnoreCase(familyName)) {
found = true;
break;
}
if(found == true) {
;
}
System.out.println(customer.returnFamilyName());
index++;
return;
}
}
It's not clear from your question what the intended behaivor actually is. Besides that, what is this ?
if (found == true);
Presumably you meant :
if (found) {
System.out.println...
}
But what if the same last name occurs twice in your list? Also why aren't using a Map instead of a List? Lookup will go from being O(n) to O(1)
Drop the ; in if (found == true); because that reads as: if this condition is true, do notihng and use braces always:
if (found == true) {
System.out.println(customer.returnFamilyName());
}
Also, include the increment inside the while loop, otherwise you are not really iterating anything.
This code seems to work because your first element happens to coincide with the searched element, try with a different one and you'll end up in a infinite loop.
Try with a version like this:
public void searchCustomer( String familyName ) {
for ( customer current : CustomerList ) {
if ( current.returnFamilyName().equalsIgnoreCase( familyName )) {
System.out.println( current.returnFamilyName() );
break;
}
}
}
Some additional remarks:
In Java clases should start with uppercase, so the class name should be declared as Customer instead of customer and variables start with lowercase, hence CustomerList should be customerList. Methods may avoid the return part and be named with a get
Also, search methods should better return the found value instead of printing it, so your final version could look like this:
public Customer searchCustomer( String familyName ) {
for ( Customer current : customerList ) {
if ( current.getFamilyName().equalsIgnoreCase( familyName ) ) {
return current;
}
}
return null;
}
You never increment index.
The code should be:
public void searchCustomer(String familyName) {
for (customer customer : CustomerList) {
if (customer.returnFamilyName().equalsIgnoreCase(familyName)) {
System.out.println(customer.returnFamilyName());
break;
}
}
}
Also, the 'customer' class should be called 'Customer' as class names should start with a capital, 'returnFamilyName' should be 'getFamilyName' as accessor methods by convention are named 'get' + the field name and 'CustomerList' should be 'customerList' as field names are supposed to start with a lowercase letter.
I would suggest try this:
System.out.println(customer.returnFamilyName());
index++;
if(found == true) { return;}
Don't forget to increment the while loop or it has the potential to run indefinitely.
You can elect to use what is known as an "enhanced for-loop", which allows you to eschew the need to increment values over CustomerList entirely. You have an object customer, so we can use that as follows:
for (customer cus: CustomerList) {
if(cus.returnFamilyName().equalsIgnoreCase(familyName)) {
System.out.println(cus.returnFamilyName());
return;
}
}
If you elect to stick with your original code (which is fine), then observe the changes in your code below.
while(index < CustomerList.size()) {
customer = CustomerList.get(index);
if (customer.returnFamilyName().equalsIgnoreCase(familyName)) {
System.out.println(customer.returnFamilyName());
break;
} else {
index++;
}
}