0

I've been writing this code for a university activity: I need to read some lines from a .txt file, store them in a HashMap and print some results based on what was on the file. The lines are a name and a number, which are that person's name and age. For example:

Mark 23

John 32

The .txt files contain some person names, the program works out well, with one exception: The first name of the list is read, stored in the HashMap, but every time I reach for it with map.get() or map.containsKey() it tells me that key doesn't exist.

This problem happens only with the first name that was read. In the example I gave, it would happen with Mark but if I change the order of the lines, to put John first, it would happen to him, instead of Mark.

Keep in mind the key is the name of the person and the value is an object Person I create for that person.

Here are my codes:

class Person {
    private String name;
    private int age;

    //Getter
    public int getAge() {
        return this.age;
    }

    public String getName() {
        return this.name;
    }

    //Constructor
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //toString
    @Override
    public String toString() {
        return name + " " + age;
    }
}
class OpenText {
    public static void textReader(String directory) {
        try {
            BufferedReader file = new BufferedReader(new FileReader(directory));
            String line;
            String[] lineSplit;

            while ((line = file.readLine()) != null) {
                lineSplit = line.split(" ");
                try {
                    int age = Integer.parseInt(lineSplit[1]);
                    Main.hMap.put(lineSplit[0], new Person(lineSplit[0], age));

                } catch (NumberFormatException exc) {
                    System.out.println(exc);
                }
            }

            file.close();
        } catch (IOException exc) {
            exc.printStackTrace();
        }
    }
}
public class Main {

    public static Map<String, Person> hMap = new HashMap<>();

    public static void main(String[] args) {
        OpenText.textReader("DIRECTORY OF THE FILE");
        System.out.println(hMap.keySet());
        System.out.println(hMap.values());
        System.out.println(hMap.get("John"));
    }

    // [John, Mark, Peter, Philip, Mary] 
    // [John 32, Mark 23, Peter 37, Philip 20, Mary 54] 
    // null
}

I guess it's clear that I'm just a newb to Java, but any insight would be much appreciated!

Thanks in advance!

Harry Coder
  • 2,429
  • 2
  • 28
  • 32
  • Please give the output of the 3 `print` you write – azro Nov 02 '18 at 13:25
  • You need to step through the code in your debugger. Most likely your String is something like `John` but not exactly e.g. it contains a whitespace or non printable character. – Peter Lawrey Nov 02 '18 at 13:26
  • 1
    Try using `\\s+` in your split method, if there is more than 1 space it'll help – azro Nov 02 '18 at 13:27
  • @azro this is the output: **[John, Mark, Peter, Philip, Mary] [John 32, Mark 23, Peter 37, Philip 20, Mary 54] null** They are in order. – Matheus Porto Nov 02 '18 at 13:28
  • 1
    Use the debugger, and add a step point at the end, at one the print, and check the content of the keys, one by one, look exactly the content of the key as a String – azro Nov 02 '18 at 13:31
  • @azro where should I place the **\\s+**? – Matheus Porto Nov 02 '18 at 13:31
  • 1
    here `lineSplit = line.split("\\s+");` – azro Nov 02 '18 at 13:31
  • 1
    You could also use trim() on your iinput, like so: Main.hMap.put(lineSplit[0].trim(), etc... – Jamie Nov 02 '18 at 13:32
  • @azro Here is the value of every variable in the HashMap: http://prntscr.com/ldk638 The resul remains being this one: http://prntscr.com/ldk6vy – Matheus Porto Nov 02 '18 at 13:34
  • I don't know what to do more, maybe open the first "HashMapNode", then open the String http://prntscr.com/ldk8kt and maybe you'll find something – azro Nov 02 '18 at 13:38
  • @Jamie just tried what you suggested, but it didn't change – Matheus Porto Nov 02 '18 at 13:38
  • @MatheusPorto Apache commons IO contains a [BOMInputStream](https://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/input/BOMInputStream.html) that can detect and filter BOM characters. Alternatively this [link](https://www.rgagnon.com/javadetails/java-handle-utf8-file-with-bom.html) contains the different type of BOM markers you need to scan for (at the start) if you want to do it manually. If you convert the string to a byte array and print it out you will see the character codes printed. – Michael Nov 02 '18 at 13:43

2 Answers2

3

Some text editors will add non printable characters to the start of the file so that when read by another text editor it know what character ending was used. e.g. https://en.wikipedia.org/wiki/Byte_order_mark

BufferedReader doesn't do anything special with these characters but instead treats them as text you can't see.

In your case, it means whatever word first actually has some nonprintable characters at the start which means it is not an exact match.

To handle arbitrary BOM, you can use the following solutions.

Byte order mark screws up file reading in Java

I would just ensure you are not adding these in the first place.

A simpler solution is to ignore these characters if that works for you.

line = line.replaceAll("[\0\uFFFD]", "");

btw

BufferedReader br = new BufferedReader(
        new InputStreamReader(
                new ByteArrayInputStream(
                        new byte[]{(byte) 0x0, (byte) 0x0, 'H', 'i', '\n'}
                )));
String line = br.readLine();
System.out.println("line.length()=" + line.length());
System.out.println(line);

prints

line.length()=4
Hi

You need to check the actual length of the String is what you expected.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Yes, this is definitely the problem. I printed the lenght of both the first and second names on the .txt file and this was the result: http://prntscr.com/ldl14y There is definitely a char I can't see there, but the solution you presented (**.replaceAll()**) did not change it. I'll take a look at the link you sent and report any progress. Thanks A LOT, man! Now I know what the issue is! – Matheus Porto Nov 02 '18 at 14:34
  • This was the solution. Turns out the text editor I was using was adding one of these non-printable characters. All I needed was to change text editors. Thank you again! – Matheus Porto Nov 02 '18 at 14:59
1

I do not know what version of Java do you use here. i tried your code with a minor chnage and it worked fine. just watch for any new blank lines between the records. Ex- you should not have the file content like :

Mark 23

John 32

if no blank line in between it works fine. here is the code i used for my main class

public class Main {
public static Map<String, Person> hMap = new HashMap<String, Person>();

public static void main(String[] args) {
    OpenText.textReader("C:\\Projects\\Trials\\directory\\src\\com\\hello\\nameList.txt");
    System.out.println(hMap.keySet());
    System.out.println(hMap.values());
    System.out.println(hMap.get("John"));
}

}

I just updated the HashMap creation to new HashMap<String, Person>();

nircraft
  • 8,242
  • 5
  • 30
  • 46
  • My file is like this: http://prntscr.com/ldkx6i I updated the creation and it did not change the result whatsoever.... Btw, I'm using java 10 – Matheus Porto Nov 02 '18 at 14:26
  • @MatheusPorto, i can't access that url in my workplace. So it would be great if you paste the contents of it here. or share it in some other way – nircraft Nov 02 '18 at 17:43