Is it possible to pass an array per parameter without instantiating it?

Asked

Viewed 83 times

1

I wanted to pass one vetor (or a ArrayList) per parameter without instantiating it, but I’m quite lost on this, because usually I instate an object list and I add the data in this list, but as I just want to pass a single element to this list, I came up with the idea that it would be possible to pass this object list without instantiating it.

Builder of my class:

public User(String email, String password, List<Role> roles) {
    this.password = password;
    this.email = email;
    this.roles = roles;
}

I tried to instantiate my object User as follows:

User user = new User(
    email, 
    passwords, 
    new ArrayList<Role>(roleRepository.findByRole("USER"))
);

Without success, I tried to create another builder:

 public User(String email, String password, Role[] roles) {
    this.password = password;
    this.email = email;
    AddNewRole(null, roles);
    this.recordLogSeparated = false;
}

And a method to pass the value to my list within my entity.

private void AddNewRole(Role role, Role [] roles ) {
    if (this.roles.isEmpty() )
        this.roles = new ArrayList<>();

    for (int i =0; i< roles.length; i++) {
        this.roles.add(roles[i]);
    }
}

Dai, now I’ve tried to instantiate my object User as follows

User user = new User(
    email, 
    passwords, 
    [roleRepository.findByRole("USER"))]
);

Is there any alternative so that it is not necessary to execute the alternatives below?

List<Role> roles = new ArrayList<Role>();
roles.add(roleRepositoryJPA.findByRole("USER"));

or

Role roles [] = {roleRepositoryJPA.findByRole("USER")};
  • 3

    It seems that you are asking if you can make a steak without killing the ox. It may not be this, but it is not very clear what you want. It’s possible you didn’t kill the ox, you can buy it at the supermarket, but someone did. You might not need the steak, you might just want a protein and it could be soy, but how do we know?

  • When you go to write a shopping list and will jot down the items on a paper you first need to have the paper. And if it is a list of a single item why create a list?

  • @Viniciusfernandes, my object may have a list, permissions, but for this scenario, initially will have a single permission

2 answers

7

If you have a constructor that receives a list, there is no way to call it without having a list (unless you pass null, of course, but I don’t think that’s the point).

So the answer to "It is possible to pass an array (or list) by parameter without instantiating it?" is nay. In fact, if you need to pass whichever object as parameter (assuming it will not pass null), you will need, at some point, to instantiate it. There is no escape from this.

The answer you accepted uses Arrays.asList, and that method also instance a list. Just because you didn’t instantiate the list directly doesn’t mean it’s not being instantiated elsewhere.

In fact the most you got with Arrays.asList was to save one or two lines of code (as you didn’t need to create the list before). But you’re still instantiating a list.

But all right, maybe what you meant is that you just wanted to save those lines even (without having to create the list directly), and expressed yourself badly by saying "without instantiating it", but it’s good to make it clear that yes, the list is being instantiated (and I’m sorry to be so repetitive, but I thought it was important to emphasize this...)


There’s another detail: Arrays.asList returns an immutable "more or less" list. So if you try to add elements in the list, it will give error. For example, if the class User have a method to add another Role:

public class User {

    public User(String email, String password, List<Role> roles) {
        this.password = password;
        this.email = email;
        this.roles = roles;
    }

    public void addRole(Role role) {
        this.roles.add(role);
    }
}

...

User user = new User(email, password, Arrays.asList(role1));
user.addRole(role2); // erro!

This code launches a UnsupportedOperationException, for the list returned by Arrays.asList does not allow new elements to be added (the same error occurs if trying to remove elements from the list). But as I said, the list returned by Arrays.asList is "more or less" immutable, since it allows you to change an existing element. For example:

public class User {
...
    public void mudaRole(Role role, int posicao) {
        this.roles.set(posicao, role);
    }
}

...

User user = new User(email, password, Arrays.asList(role1));
user.mudaRole(role2, 0); // muda a Role da posição 0 da lista

In this case the code works, because the list returned by Arrays.asList allows you to change the widget at an existing position.

Depending on how you will manipulate the list of roles, That may or may not make a difference. That’s why it’s important to know the implication of every method you use, and not simply use it to "save a line of code". A smaller code is not necessarily "better".


Alternative: varargs

An alternative to "save lines" is to use varargs:

public User(String email, String password, Role... roles) {
    this.password = password;
    this.email = email;
    this.roles = Arrays.asList(roles);
}

...
// pode passar uma Role
User user = new User(email, password, role1);

// ou pode passar várias de uma vez
User user = new User(email, password, role1, role2, role3);

The syntax Role... roles indicates that you can pass one or more roles (or none, in which case the list will be empty).

Internally, the JVM "converts" these parameters to an array of Role, so it is still necessary to convert it to a list. I used Arrays.asList, but you could create it another way if you wanted to. For example:

this.roles = new ArrayList<>(Arrays.asList(roles));

This case is a little different: I create a list of all the roles (using Arrays.asList), and create a ArrayList containing the elements of this list. The difference here is that this list is not "immutable means" as it occurs if I just call Arrays.asList (with the ArrayList I can add and remove elements).

In addition, with varargs you hides the internal implementation of the class: whether or not the roles are in a list, an array or any other internal structure, this is class implementation detail User; who create the user only needs to pass the roles he has, without knowing if within the class he will create a list or not (and if one day this internal implementation changes, the other classes need not know, because the constructor will continue to receive the roles in the same way).

But of course, if the roles get on a list, then you’ll still be instantiating a list (who creates the User no need, just pass the roles to the builder, but within the class User has an instance being created). I think I’ve said that can not escape this, right?

  • 1

    Thank you for the @hkotsubo reply, very well explained.

2


If I understand your question correctly, you want to pass directly a list of objects, I believe the code below work:

User user = new User(
email, 
passwords, 
Arrays.asList(roleRepository.findByRole("USER"))
);
  • Thank you my dear, that’s exactly what I was looking for...

Browser other questions tagged

You are not signed in. Login or sign up in order to post.