3

I have a class, Student with this constructor.

 public Student(String name, int age, Map<String, Integer> grades) {
    this.setName(name);
    this.setAge(age);
    this.setGrades(grades);
 }

when creating a Student object, how do I pass the Map argument in the constructor?

What am looking for is something similar to this:

List<Student> roster = new ArrayList<>();
roster.add(new Student("Ann Droid", 145, Arrays.asList(96, 78)));

If I had this constructor:

public Student(String name, int age, List<Integer> grades) {
    this.setName(name);
    this.setAge(age);
    this.setGrades(grades);
 }
2
  • Java does not support a map literal ;( And I know of no helper function that does what you want like Array.asList. Commented May 19, 2015 at 8:34
  • I am not sure what you are trying to achieve, but if you want to pass the argument "for testing" you could consider sending a mock. Not sure I would do it for a simple Map though, just something to consider. Commented May 19, 2015 at 8:35

5 Answers 5

5

Vanilla flavor plain Java doesn't have anything for Maps as Arrays.asList(). So you will have to initialize the Map over several line of code like this:

Map<String, Integer> grades = new HashMap<String, Integer>();
grades.put("English", 90);
roster.add(new Student("Ann Droid", 145, grades);

However, with Google's Guava you can do this:

Map<String, Integer> grades = ImmutableMap.of("English", 90);
Sign up to request clarification or add additional context in comments.

1 Comment

3

It can't be done with a one liner.

Map<String,Integer> grades = new HashMap<>();
grades.put("Math", 100);
roster.add(new Student("Ann Droid", 145, grades));

5 Comments

Well it can, if you make a utility vararg function as in Maps.map("Math", 100, "Physics", 70)
@WouterLievens Well, I can argue that writing such a utility requires more than one line of code, so it still won't be a one liner :)
@WouterLievens Guava's ImmutableMap is essentially what are you are referring to here. It appears to be a one-liner, but behind the scenes the Map is getting initialized.
Hi @Eran what do you think of the answer from @SanyaLuc? It's a one-liner no?
@ojonugwaochalifu It works, but I wouldn't use anonymous class for the sake of having a one liner. I think it's less readable.
3

You can make a utility function yourself. It's not very type-safe, though, because you need to circumvent typing to (ab)use the varags parameter.

public class MapExample
{
    public static <K, V> Map<K, V> map(Object... objects)
    {
        Map<K, V> map = new HashMap<>();
        for (int n = 0; n < objects.length; n += 2)
        {
            map.put((K)objects[n], (V)objects[n + 1]);
        }
        return map;
    }

    public static void main(String[] args)
    {
        System.out.println(map("AAA", 123, "BBB", 456));
    }
}

1 Comment

Thanks! I'm not saying it's superior or the best solution, but it works. A good alternative would be to have a generic builder... you can probably do that with generic typesafety.
3

There's no way to create a Map in a one-liner with Java <= 7 and with the standard JDK. (Well you could technically with a double brace initializer, but it's considered as a bad practice).

In Java 8, you could use the Stream API to achieve this:

import java.util.AbstractMap.SimpleEntry;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toMap;

...
new Student("Name", 
            10,
            Stream.of(new SimpleEntry<>("MyString", 1), 
                      new SimpleEntry<>("AnotherString", 2))
                  .collect(toMap(SimpleEntry::getKey, SimpleEntry::getValue)));

Now you have to see it if improves readability or not for your use case ;)

Or you could modify your design so that the Map<String, Integer> is represented with a List<Grade> instead, with each Grade having a String representing the course and an Integer for the Student's mark for this course.

And then you could use Arrays.asList:

new Student("John", 
            18, 
            Arrays.asList(new Grade("French", 1), new Grade("Math", 5)));

Of course you have to ensure uniqueness of the grades.

5 Comments

Not very far from a map literal ;)
Just a personal opinion but if I saw that code in a code review, it would die
The functional programming people are trying to take over Java, and I hope I become a project manager before that happens ^ ^
@MrSpoon I wish that there is something like HashMap.of(...) in the standard JDK... :-)
You could ensure the uniqueness of the grades by using a Set instead of a List and implementing equals & hashCode in the Grade class, only using the subject name (not the value of the grade).
1

You can try this option using an anonymous constructor

List<Student> roster = new ArrayList<Student>();
roster.add(new Student("Ann Droid", 145, new HashMap<String, Integer>(){{
                                         put("English", 78);
                                         put("Math", 96);
                                         }}));

Or you can use Guava ImmutableMap of(), but this API is limited to five pairs.

List<Student> roster = new ArrayList<>();
roster.add(new Student("Ann Droid", 145, ImmutableMap.of("English", 78, "Math", 96);

1 Comment

Works, but you have to change HashMap<>() {{.. to HashMap<String, Integer>() {{..

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.