0

Coming from a JavaScript background, I find the following code a bit too robust, containing multiple statements; and am wondering how I can simply the code, and do everything in a single statement.

enter image description here

Student is the superclass and Friend and Schedule are the subclasses aggregated into a superclass ArrayList public member (these are not nested classes). Here is my current code:

public static void main(String[] args) {

  // Subclass1 instantiation and declaration
  Friend friend_of_andy_1 = new Friend(1002, "Bob");
  ArrayList<Friend> andys_friends = new ArrayList<>();
  andys_friends.add(friend_of_andy_1);    // superclass member

  // Subclass1 instantiation and declaration
  Schedule schedule_of_andy_1 = new Schedule(1, "Yoga practice");
  ArrayList<Schedule> andys_schedule = new ArrayList<>();
  andys_schedule.add(schedule_of_andy_1); // superclass member

  // Superclass instantiation declaration with subclass objects in constructor argument
  Student student_andy = new Student(1001, "Andy", andys_friends, andys_schedule);

}

I'm wondering if I can do something like this instead, where I declare/instantiate the superclass and subclasses in a single statement; is this possible?

public static void main(String[] args) {

  Student student_andy = new Student(
    1001,
    "Andy",
    // instantiation of subclass
    ArrayList<Friend>[
      Friend(
        {
          1002,
          "Bob"
        }
      )
    ],
    ArrayList<Schedule>[
      Schedule(
        {
          1,
          "Yoga practice"
        }
      )
    ]
  )

};
Jim22150
  • 511
  • 2
  • 8
  • 22

2 Answers2

2

First, you only use friend_of_andy_1 in one place, so you can eliminate it:

List<Friend> andys_friends = new ArrayList<>();
andys_friends.add(new Friend(1002, "Bob"));

Second, if you're ok with the list having fixed size, i.e. you cannot add more elements to it, you can use Arrays.asList(), instead of creating an ArrayList:

List<Friend> andys_friends = Arrays.asList(new Friend(1002, "Bob"));

Then you can do the same for Schedule and inline that in the creation of Student:

Student student_andy = new Student(1001, "Andy",
                                   Arrays.asList(new Friend(1002, "Bob")),
                                   Arrays.asList(new Schedule(1, "Yoga practice")));

If the lists must be resizable, then use the ArrayList​(Collection<? extends E> c) constructor:

Student student_andy = new Student(
        1001,
        "Andy",
        new ArrayList<>(Arrays.asList(
                new Friend(1002, "Bob")
        )),
        new ArrayList<>(Arrays.asList(
                new Schedule(1, "Yoga practice")
        ))
);

And of course format that however you want, if you prefer the exploded style that takes up way too many lines of code:

Student student_andy = new Student(
    1001,
    "Andy",
    new ArrayList<>(
        Arrays.asList(
            new Friend(
                1002,
                "Bob"
            )
        )
    ),
    new ArrayList<>(
        Arrays.asList(
            new Schedule(
                1,
                "Yoga practice"
            )
        )
    )
);
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • Yes it needs to be resized, could you explain how the lists could be resized later after new Student has been constructed? -- using ArrayList​(Collection extends E> c) – Jim22150 Feb 04 '18 at 00:32
  • @Jim22150 `student_andy.addFriend(new Friend(1007, "John"));` where `addFriend(Friend friend)` is implemented as `this.friends.add(friend);` --- Did you truly just ask how to add something to a `List`? – Andreas Feb 04 '18 at 00:34
  • 2
    @Jim22150 Lists don't need to be explicitly resized. If they're resizable, then you can just add things to them as required using the `add` method. The lists created by `Arrays.asList` are not resizable, which is why the second half of this solution builds additional lists from the ones created by `Arrays.asList`. – Dawood ibn Kareem Feb 04 '18 at 00:37
1

Ok, so, essentially, you are missing JSON [footnote-1] too much? Understandable.

Below is a loose collection of methods for creation of instances in Java so that it looks like JSON as much as possible.

1) Arrays: Use inline array literals

They are slightly more verbose in Java, but almost as good as [ ... ] in JSON, e.g. :

new int[]{1, 2, 3}

is a literal for an array of integers.

2) Objects: Define proper constructors

If your Friend has a constructor public Friend(int id, String name), then initializing Friends is really easy and pleasant:

new Friend(1234, "Bob")

3) More objects, faster use factory methods

If you define factory methods, you can get rid of new. E.g. if you have

class Friend {
    ...
    static Friend friend(int id, String name) { return new Friend(id, name); }
}

then you can even get rid of new. This is useful in those seldom cases where you are defining some kind of embedded-DSL, and really need this constructor thousand times.

4) Lists: Use asList

You can import static methods using static imports in Java:

import static java.util.Arrays.asList;

now you have the handy asList available, so that

asList(friend(2, "John"), friend(3, "Bob"))

gives you a list of friends.

5) Maps: Use anonymous subclasses with initializer blocks.

This seemingly crazy thing works in java:

HashMap<String, Integer> hm = new HashMap<>{{
  put("foo", 10);
  put("bar", 20);
}};

this is because the inner pair of curly braces encloses an initializer block, in which you can call methods on this.

Ok, now you can easily create:

  • Primitive stuff: Strings, ints, doubles
  • User-defined objects (using constructors and factory methods)
  • Arrays
  • Lists
  • Maps

This should be enough to create ad-hoc json-esque data structures in Java.


Now, assuming that all constructors are in place, your code becomes this:

import static java.util.Arrays.asList;

...

Student student_andy = new Student(
  1001,
  "Andy",
  asList(new Friend(1002, "Bob")),
  asList(new Schedule(1, "Yoga practice"))
)

We didn't use maps here, so the hint with initializer block is just a bonus.

[footnote-1] To be more precise: it seems as if you are missing the fragment of JavaScript which allows to easily initialize those objects which canonically map to JSON objects. JSON is of course not JavaScript. Thanks @Andreas for pointing that out.

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
  • Thanks, this looks like a great set of tools to try out. Yes, indeed, missing JSON; however, will be reading in actual JSON data. So I can see where I could definitely use your suggestions when looping through the external data. – Jim22150 Feb 04 '18 at 00:46
  • 1
    Note that there are already very robust standard libraries for parsing JSON for Java, so those tricks are probably less useful when dealing with JSON itself. However, I find it occasionally useful for setting up small test cases, where I need a few small concrete data structures quickly. – Andrey Tyukin Feb 04 '18 at 00:48
  • can you recommend a JSON library for NetBeans? – Jim22150 Feb 04 '18 at 00:53
  • You make 5 points, then only use one of them in the solution at the bottom. *Wow!* TL'DR much? – Andreas Feb 04 '18 at 00:59
  • 1
    @Andreas Don't give a man a fish. Give him a fishing rod! Ah what, forget the fishing rod, *give him a freakin' fishing trawler!!* ;) No, seriously. I just saw that the underlying problem is that the OP is missing JSON. I didn't want that he misses JSON too much. So I gave *all* the necessary pieces at once. I hope that solves the underlying problem, and not only the problem with those three object instances. – Andrey Tyukin Feb 04 '18 at 01:04
  • @AndreyTyukin FYI: OP is not missing JSON, OP is missing **JavaScript**. JSON is a data exchange format, JavaScript is a programming language. Huge difference, even though a *small* part of JavaScript happens to look similar to JSON. Please don't mix the two, spreading confusion to readers on this site. – Andreas Feb 04 '18 at 01:12
  • 1
    @Jim22150 Netbeans is just an IDE. It doesn't care which project dependencies you use. There are various libraries to deal with JSON, e.g. `javax.json` or `org.json` [see here](https://stackoverflow.com/questions/29042622/which-one-to-use-jsonobject-from-org-json-vs-jsonobject-from-javax-json) and there are also slightly more sophisticated tools like `jackson` and `gson`. It depends what you want to do with it: do you want to have access to raw parsed json data, or do you want to map it to **P**lain**O**ld**J**ava**O**bjects automatically? Just follow the links, take a look around. – Andrey Tyukin Feb 04 '18 at 01:13
  • Andrey, those are all good points, but you seem to have given him a fishing trawler with a tank full of fish that have already been caught. – Dawood ibn Kareem Feb 04 '18 at 01:17
  • @Andreas yes, thanks for pointing that out. You are of course absolutely right. I meant something like "Sublanguage of JavaScript which is isomorphic to JSON". I added a footnote, I hope it's less confusing now. – Andrey Tyukin Feb 04 '18 at 01:21
  • no footnote needed, yes, I'm missing JS object notation; the original assumption was correct lol – Jim22150 Feb 04 '18 at 01:26
  • @DawoodibnKareem I'm not sure how to interpret that statement. The knowledge how to initialize small simple objects is certainly rather a *tool* and not a pile of dead fish, isn't it? I use it all myself occasionally... – Andrey Tyukin Feb 04 '18 at 01:26
  • I wasn't looking for a "solution".. Andrey definitely helped with what my question was inferring – Jim22150 Feb 04 '18 at 01:27