Search code examples
javastringexceptioniofile-read

How can exception message overtake an executed printed line


I read fields from a .csv file separated with ";" semicolons. And I wrote exeptions to handle the possible deviations. But if there is an exception, the NetBeans read out the error message before the last line.

This is how the output look like: enter image description here

I don't understand how is possible that the later line in the code can print out prevously. This is my whole code:

public static void reader(String fileName) throws IOException {
    try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
        String line;
        List<String> lineHolder = new ArrayList<>();
        StringTokenizer divider;
        String formatter = "%2s|%-30s|%-30s|%10s|%n";

        String separator = "----------";
        System.out.format("ID|%-30s|%-30s|birth date|%n", "name", "email");
        System.out.print("--+" + separator + separator + separator 
                + "+" + separator + separator + separator + "+" 
                + separator + "+\n");

        while ((line = br.readLine()) != null){
            if (line.startsWith("#", 0))
                continue;
            if (!line.contains(";")) {
                throw new IOException("too less data or not proper delimiter");
            }
            divider = new StringTokenizer(line, ";");
            lineHolder = arrayFiller(divider);
            dataChecker(lineHolder, line);
            System.out.format(formatter, lineHolder.get(0), lineHolder.get(1)
                , lineHolder.get(2), lineHolder.get(3));
        }
    } catch (FileNotFoundException ex) {
        System.err.println("The file not found.");
    } catch (IOException ex){
        System.err.println(ex.getMessage());
    }
    System.out.print("\n");
}

public static ArrayList<String> arrayFiller(StringTokenizer divider) {
    ArrayList<String> lineHolder = new ArrayList<>();
    while (divider.hasMoreTokens()) {
        lineHolder.add(divider.nextToken());
    }
    return lineHolder;
}

These are the exceptions:

public static void dataChecker(List<String> lineHolder, String line) throws IOException {
    if (lineHolder.size() < 4) {
        throw new IOException("too less data or not proper delimiter");
    } else if (lineHolder.size() > 4) {
        throw new IOException("too much data");
    } else if (lineHolder.get(0).length() > 2 
            || !Pattern.matches("[0-9]+", lineHolder.get(0))) {
        throw new IOException("Error during reading the file: "
                + "not proper ID field format");
    } else if (lineHolder.get(1).length() > 30 
            || !Pattern.matches("[a-zA-ZíÍöÖüÜóÓőŐúÚűŰáÁéÉ. ]+", lineHolder.get(1))) {
        throw new IOException("Error during reading the file: "
                + "not proper Name field format");
    } else if (lineHolder.get(2).length() > 30 
            || !Pattern.matches("[a-zA-Z0-9@. ]+", lineHolder.get(2))) {
        throw new IOException("Error during reading the file: "
                + "not proper Email field format");
    } else if (lineHolder.get(3).length() > 10 || dateFormatter(lineHolder.get(3))) {
        throw new IOException("Error during reading the file: "
                + "not proper Birth date field format");
    } 
}

public static boolean dateFormatter(String datum) {
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    try {
        LocalDate changedDate = LocalDate.parse(datum, dtf);
        return false;
    } catch (DateTimeParseException ex) {
        return true;
    }
}

And the source file:

#ID;name;email;birth date
1,Jakob George,[email protected],1981-11-23
2;Susan Smith;[email protected];1982-12-01
3;Poul Drake;[email protected];1990-01-02
4;Isaac Wheather;ruck%[email protected];1988-01-22
5;George T. Benson;[email protected];1977-08-12

I tried to put the method (holder of exceptions) into the reader() method but the reasult the same. How is this possible and what I did wrong?


Solution

  • Error messages are printed through a different output stream. The standard output stream stdout is for normal logging/output, errors (via System.err.println) go to stderr. Your console/terminal shows both, but they won't wait for each other to finish printing stuff.

    EDIT: Maybe this helps, too.

    EDIT2: If you change the error out to print to a file instead, you will lose error output in the console/terminal. But maybe that's OK for you? Like this:

    //set err out to print to file
    PrintStream ps = new PrintStream("err.log");
    System.setErr(ps);
    
    //cause exception for testing it
    String s = null;
    s.length();
    

    If you want to have both errors and standard output printed to the console/terminal, there's no way to control the timing of both streams, as each printed line is an independent operation.