I have a plain text file with some data that I can't change, so I have to create a datastructure to use in reading the file and with that datastructure do some thousands of interactions. The file follows a defined pattern like this:AAAAAA:zz_something sometxt1 sometxt2AAAAAA:zz_something sometxt1 sometxt2AAAAAA:zz_someotherthing sometxt1 sometxt2BBBBBB:zz_something sometxt1 sometxt2BBBBBB:zz_someotherthing sometxt1 sometxt2BBBBBB:zz_something sometxt1 sometxt2CCCCC:zz_others blahblah blehblehDDDDD:blihblih blohblohEEEEE:bluhbluhThis text is divided basically in three parts (most of it) first, before the :, would be my object1second, after the : AND IF it starts with zz_, would be my object2third, everything else from that point on would be a List of stringsfor the part after : that does not start with zz_ I will use a default string to identify it.At first I thought of creating three objects with this structure: obj1                       obj2                 obj3    String id                 String id            String str1    Set<String> obj2          List<obj3> list      String str2Plus a main object that would hold a Set<Obj1> main. But when I start to implement this structure I realize that it would be very difficult to read this in a loop to get any element inside it, like main.get('obj1').get('obj2').list, because it is a Set and I cannot do that.So I ended up using a map as Map<String, Map<String, List<String>>> main but I feel like there must be a better way to do this.What would be your recomendations?
Best approach to a defined datastructure
java;data structures
I come from a perl background.  There, the combination of having autovivification and easy nested hash/list structures... the nested maps don't look too bad if you can keep your head around them.  But on the other hand, they aren't that great either and it's really easy for a null pointer to creep in with other languages.  In more formal languages, that you display your implementation makes refactoring a nightmare.  It's certainly less than optimal or idiomatic Java code.So, we've got three objects.  They're nested.  And that, while it can make it a bit awkward, you might want to look at actually making them nested classes.One    Two          ThreeAAAAAA:zz_something sometxt1 sometxt2AAAAAA:zz_something sometxt1 sometxt2AAAAAA:zz_someotherthing sometxt1 sometxt2In this example, you would have a class One, Two, and Three.  Class One would have an associated id of 'AAAAAA' and then other stuff.  So you could have a definition akin to:class One {    String id;    Map<String, Two> data;    public void One() { id = null; data = new HashMap(); }    public void build(String line) throws IllegalArgumentException {        parse line;        if (id == null) { id = parsedId; }        else { throw new IllegalArgumentException(attempt to reset id); }        if data.contains(twoId) {            two = data.get(twoId);        } else {            two = new One.Two();            data.put(twoId, two);        }        two.build(line);    }    public static class Two {        // ....        private void build(String line) {            // ....            three = new One.Two.Three();            three.build(line);        }    }}Note that the Two.build method is private.  Because it's a nested class, the outer class can access the inner class private members and methods.  This allows you to restrict the building of Two (and Three) to the public interface that One provides.  This prevents other code from tinkering with it and messing it up later.Furthermore, while this doesn't have all the access methods, they would be provided via the public interface of One in accordance with the Law of Demeter.Yes, underneath this, this is a Map<String, Map<String, List<String>>> - because that is what the data is.  However, its one that doesn't disclose its implementation, or make a mess.  Its still up to you to write methods of one.find(sometxt2) which returns zz_something if you want it, but it makes it much easier for the person using the object to do so. This in turn makes them less likely to make errors with the code (even if that person is you) and reduces the cognitive load allowing faster development and less worry about what is going on.This also encourages dry code in that you won't be writing the code for find(String arg) again and again and again each time you need it... or writing a 'helper' class with static methods that work on the data.  When you find yourself writing SomeDataHelper classes or SomeDataUtil classes, you've likely got a class in there that wants to escape into a form akin to the one described above.As an alternative to the nested class, one could use a package to hold the three classes and make the methods package protected (default protection - not public, or protected, or private) instead.  This could make serialization easier and avoid what could very well be a java file that is three times longer (its three classes).