Home > Software engineering >  System.exit(0) only in Main and not in called classes
System.exit(0) only in Main and not in called classes

Time:07-07

I am not a Java developer but a Product Manager and I am doing just a basic Java course. As a final assignment I developed a small applications which works just fine. I only have one issue left that I would like to solve before sending it in. It concerns the location of System.exit(0). I want it to be done in Main only, but facing some problems getting the code to do this right.

In Main a piece of the code looks like this, and there are several other similar lines of code with the same problem:

ArrayList<BeschikkingenSelectieDatums> ingelezenDatums = InlezenBestandMetDatums.inlezenTabel();
if (ingelezenDatums.isEmpty())
{
    System.exit(0);
}

The class being called looks like this:

public class InlezenBestandMetDatums 
{
    private static final String BESTAND_MET_DATUMS = "****.csv";
    private static final String SCHEIDINGSTEKEN_IN_BESTAND = ";";
    
    public static ArrayList<BeschikkingenSelectieDatums> inlezenTabel() 
    {
        ArrayList<BeschikkingenSelectieDatums> resultaatIngelezenBestand = new ArrayList<BeschikkingenSelectieDatums>();
        String regelInBestandMetDatums = "";
        DateTimeFormatter datumTijdFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");

        try(Scanner scanner = new Scanner(new File(BESTAND_MET_DATUMS)))    
        {
            while(scanner.hasNext()) 
            {
                regelInBestandMetDatums = scanner.next();
                
                BeschikkingenSelectieDatums datumsIngelezenNaSplit = new BeschikkingenSelectieDatums(
                    LocalDate.parse(regelInBestandMetDatums.split(SCHEIDINGSTEKEN_IN_BESTAND)[0], datumTijdFormatter), 
                    LocalDate.parse(regelInBestandMetDatums.split(SCHEIDINGSTEKEN_IN_BESTAND)[1], datumTijdFormatter));
                        
                //Als er niets fout is kan de ArrayList worden gevuld
                resultaatIngelezenBestand.add(datumsIngelezenNaSplit);
            }
        }
    
        //Valideren datum
        catch(DateTimeException ex)
        {
            OutputNaarGebruikerAfhandeling.FoutmeldingTonenIndienFouteDatumInCSVBestandAanwezig("Beschikkingenselectie datums",regelInBestandMetDatums.split(SCHEIDINGSTEKEN_IN_BESTAND)[0] );
            OutputNaarGebruikerAfhandeling.FoutmeldingTonenIndienFouteDatumInCSVBestandAanwezig("Beschikkingenselectie datums",regelInBestandMetDatums.split(SCHEIDINGSTEKEN_IN_BESTAND)[1] );
            System.exit(0);     //Deze moet eigenlijk hier nog weg en in main gesloten worden.
        }    
        
        //Valideren aanwezigheid bestand
        catch(IOException e)
            
        {OutputNaarGebruikerAfhandeling.FoutmeldingTonenIndienCSVBestandNietAanwezig(e.getMessage(), "Beschikkingenselectie datums");            
        }       
        return resultaatIngelezenBestand;
     }}

So what I have done is create a few Exceptions and in the case the CSV file was not found the ArrayList will be empty and in Main the application will stop. The other Exceptions will lead to stopping the application within the class itself. However I would like to sent a signal to Main that an Exception occurred and Main then decides to stop the application.

What do I need to change or probably add to get this done?

I'm sure the code probably has more issues than this, but right now I would like to focus on this particular problem. Unless of course the current code itself is the reason why I can't solve this.

Any help would be appreciated.

CodePudding user response:

The simplest explanation and solution I can provide (Since you pointed out that you just want to get it done, the solution proposed will lack a lot of "why"-s):

Explanation:

You are using exceptions incorrectly. With exceptions you can

  1. Force error handling or terminate the application if your errors are left unchecked.
  2. Propagate errors to the place in your code where you actually want to do error handling.

You are making your own work harder by catching your exceptions early and then trying to figure out how to propagate the error to main. But that is the point of exceptions. Don't catch them where you don't want to handle them. Let them propagate up in the call-chain to the place where you actually want to do something with them.

Solution:

To every function where you catch your exceptions, just add a "throws" to the "header" of the function.

Eg.:

public static ArrayList<BeschikkingenSelectieDatums> inlezenTabel() throws DateTimeException {
...
}

And omit the

catch(DateTimeException ex) {...}

block from the function.

This will in turn, let the DateTimeException propagate up to the caller where it will be the callers job to handle the exception.

Now if you do something similar to all your functions and then handle all the exceptions in a try-catch in the main function and call the System.exit in that catch, then you are done.

Note:

I kept this brief but you should read up on exceptions and exception handling to properly execute and understand the solution.

CodePudding user response:

You can throw an exception when the ArrayList is empty

ArrayList<BeschikkingenSelectieDatums> ingelezenDatums = InlezenBestandMetDatums.inlezenTabel();
if (ingelezenDatums.isEmpty())
{
   throw new Exception("Empty ArrayList Exception");
}

And use throws after the method name that is throwing an exception, So that it can be handled on the method call using the try-catch block forcefully.

public static ArrayList<BeschikkingenSelectieDatums> inlezenTabel() throws Exception {
   // your code
}

Handling Exception:

InlezenBestandMetDatums myObj = new InlezenBestandMetDatums();
try {
   ArrayList<BeschikkingenSelectieDatums> = myObj.inlezenTabel();
} catch (Exception e) {

   System.exit(0);
}

CodePudding user response:

As you want to handle the exceptions in the main you should add the exceptions to the signature of the methode. The consequence is that now the caller has to handle/catch the maybe throwing exceptions. So do this:

    public class InlezenBestandMetDatums {
        private static final String BESTAND_MET_DATUMS = "****.csv";
        private static final String SCHEIDINGSTEKEN_IN_BESTAND = ";";

        public static List<BeschikkingenSelectieDatums> inlezenTabel() throws IOException, DateTimeException {
            List<BeschikkingenSelectieDatums> resultaatIngelezenBestand = new ArrayList<BeschikkingenSelectieDatums>();
            String regelInBestandMetDatums = "";
            DateTimeFormatter datumTijdFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");

            try (Scanner scanner = new Scanner(new File(BESTAND_MET_DATUMS))) {
                while (scanner.hasNext()) {
                    regelInBestandMetDatums = scanner.next();

                    BeschikkingenSelectieDatums datumsIngelezenNaSplit = new BeschikkingenSelectieDatums(
                        
                    LocalDate.parse(regelInBestandMetDatums.split(SCHEIDINGSTEKEN_IN_BESTAND)[0], datumTijdFormatter),
                        LocalDate.parse(regelInBestandMetDatums.split(SCHEIDINGSTEKEN_IN_BESTAND)[1], datumTijdFormatter));

                    //Als er niets fout is kan de ArrayList worden gevuld
                    resultaatIngelezenBestand.add(datumsIngelezenNaSplit);
                 }
            }
            return resultaatIngelezenBestand;
       }
    }

Some Recommendations

  1. Use the more general type for your variables and methods as you can, because it doesn't change the logic if you would use an LinkedList instaed. So use ArrayList<...> someList = ArrayList<>() only if you need methods that ArrayList has and other Lists doesn't.

  2. In general try to use english for your variables and methods to give the possible reader of your code the change to read understand your variables better, this is common practice

  • Related