1

I am working on a simple project in which a tab delimited text file is read into a program.

My problem: When reading the text file there are regularly empty data spaces. This lack of data is causing an unexpected output. For lines that do not have data in the token[4] position all data read is ignored and "4" is displayed when I run a System.out.println(Just a test that the data is being read properly). When I incorporate a value in the token[4] position the data reads fine. It is not acceptable that I input a value in the token[4] position. See below for file and code.

2014    Employee    Edward Rodrigo  6500
2014    Salesman    Patricia Capola 5600    5000000
2014    Executive   Suzy Allen  10000   55
2015    Executive   James McHale    12500   49
2015    Employee    Bernie Johnson  5500    
2014    Salesman    David Branch    6700    2000000
2015    Salesman    Jonathan Stein  4600    300000
2014    Executive   Michael Largo   17000   50
2015    Employee    Kevin Bolden    9200    
2015    Employee    Thomas Sullivan 6250    

My code is:

// Imports are here
import java.io.*;
import java.util.*;

public class EmployeeData {

public static void main(String[] args) throws IOException {
    // Initialize variables
    String FILE = "employees.txt";  // Constant for file name to be read
    ArrayList<Employee> emp2014;    // Array list for 2014 employees
    ArrayList<Employee> emp2015;    // Array list for 2015 employees
    Scanner scan;

    // Try statement for error handling
    try {
        scan = new Scanner(new BufferedReader(new FileReader(FILE)));
        emp2014 = new ArrayList();
        emp2015 = new ArrayList();

        // While loop to read FILE
        while (scan.hasNextLine()) {
            String l = scan.nextLine();
            String[] token = l.split("\t");
            try {
                String year = token[0];
                String type = token[1];
                String name = token[2];
                String monthly = token[3];
                String bonus = token[4];
                System.out.println(year + " " + type + " " + name + " " + monthly + " " + bonus);
            } catch (Exception a) {
                System.out.println(a.getMessage());
            }
        }
    } catch(Exception b) {
        System.out.println(b.getMessage());
    }
}

}

The output I receive for lines with "Employee" returns in an unexpected way.

Output:

run:
4
2014 Salesman Patricia Capola 5600 5000000
2014 Executive Suzy Allen 10000 55
2015 Executive James McHale 12500 49
4
2014 Salesman David Branch 6700 2000000
2015 Salesman Jonathan Stein 4600 300000
2014 Executive Michael Largo 17000 50
4
4
BUILD SUCCESSFUL (total time: 0 seconds)

I tried to use an if-then to test for null value in token[4] position but that didn't really help me. I've done quite a bit of searching with no success.

I am still very new to the programming world, so please pardon my coding inefficiencies. Any support and general feedback to improve my skills is greatly appreciated!

Thank you, Bryan

Zeeboot
  • 49
  • 7

2 Answers2

0

This is happening because you are actually getting an ArrayOutOfBoundsException and the message for that is '4'. Because the index of 4 is greater than the length of the array. You should put in your catch statement b.printStackTrace() as this will give you greater details when ever the caught exception occurs.

You can get around this by adding the following:

String bonus = "";
if(token.length > 4)
    bonus = token[4];
Java Devil
  • 10,629
  • 7
  • 33
  • 48
  • 1
    A ternary can also be used. `String bonus = token.length > 4 ? token[4] : "";` – 4castle May 24 '16 at 04:39
  • 3
    Or better yet, don't `catch (Exception)` at all - let unexpected exceptions propagate out of `main()` (like OP is already doing for `IOException`). Catching `Exception` is very rarely what you want to do. – dimo414 May 24 '16 at 04:39
  • Thanks a lot for the help! I will give this a try. – Zeeboot May 24 '16 at 04:40
  • @4castle Yes it can, decided to keep it simple as OP said they were new to programming :) – Java Devil May 24 '16 at 04:41
  • @dimo414 my understanding of exception handling is in its infancy. Thanks a lot for the feedback. – Zeeboot May 24 '16 at 04:41
  • @dimo414 Yes I agree. Was merely pointing out what was happening :) – Java Devil May 24 '16 at 04:44
  • @dimo414 is right and the fundamental problem here is catching Exception and its unintended consequences. It ends up catching things you probably didn't mean to catch depriving you of the detailed error reporting that would let your reason about your actual root cause issue. Adding a 'throws' is generally a better idea than a catch-all – pvg May 24 '16 at 04:44
  • @pvg By printing the stack trace you get the details. In this particular case yes the try-catch is actually not required, but I disagree with throwing as a general approach. A better approach in general would be catch the exceptions you can and deal with them gracefully where you can. That aside, this is not a question about exceptions and the best way to deal with them. – Java Devil May 24 '16 at 04:53
  • @JavaDevil The code does not print the stack trace neither does your answer. Catching `Exception` catches RTEs which is a terrible idea and hides avoidable bugs - in fact, that's the intended distinction between checked and unchecked exceptions. – pvg May 24 '16 at 05:29
  • @pvg What part of `printStackTrace()` does not print the stack trace? Yes catching All exceptions is a terrible idea, I never said it was a good idea, was trying to say catching checked exceptions and dealing with them is generally better than throwing them, and again **NOT** a question about best Exception practices – Java Devil May 24 '16 at 05:46
0

Java Devil is right that the underlying issue because of an ArrayOutOfBoundsException. But it's also worth exploring why you didn't see that. As we discussed in the comments your "Try statement for error handling" is in fact not handling your errors at all, instead it is suppressing them, which is generally a poor plan as it allows your program to continue running even after your assumption (that it works correctly) has been violated.

Here's a slightly cleaned up version of your code. The underlying problem that causes the ArrayOutOfBoundsException is still there, but the issue would be immediately apparent if you'd structured your code this way instead. There's a few comments calling out issues inline.

public class EmployeeData {
  // constants should be declared static and final, and not inside main
  private static final String FILE = "employees.txt";

  // If you have an exception and you don't know how to handle it the best thing
  // to do is throw it higher and let the caller of your method decide what to do.
  // If there's *nothing* you want to do with an exception allow main() to throw
  // it as you do here; your program will crash, but that's a good thing!
  public static void main(String[] args) throws IOException {
    // Notice the <> after ArrayList - without it you're defining a "raw type"
    // which is bad - https://stackoverflow.com/q/2770321/113632
    ArrayList<Employee> emp2014 = new ArrayList<>();
    ArrayList<Employee> emp2015 = new ArrayList<>();

    // A try-with-resources block automatically closes the file once you exit the block
    // https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
    try (Scanner scan = new Scanner(new BufferedReader(new FileReader(FILE)))) {
      while (scan.hasNextLine()) {
        String l = scan.nextLine();
        String[] token = l.split("\t");
        // The code below this line assumes that token has at least five indicies;
        // since that isn't always true you need to handle that edge case before
        // accessing the array indicies directly.
        String year = token[0];
        String type = token[1];
        String name = token[2];
        String monthly = token[3];
        String bonus = token[4];
        System.out.println(year + " " + type + " " + name + " " + monthly + " " + bonus);
      }
    }
  }
}
Community
  • 1
  • 1
dimo414
  • 47,227
  • 18
  • 148
  • 244