• Post Reply Bookmark Topic Watch Topic
  • New Topic

Get/Set methods and arrays? What's the "right" (or righter) way to do it?  RSS feed

 
Phong Tran
Greenhorn
Posts: 8
Firefox Browser IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi everyone,

I'm new to these forums, I always thought it would be cool to contribute as well as take away from this forum but always felt that I didn't have the expertise to put forth my ideas... or have questions that I couldn't get answered by simply Googling. But today I figured, nah forget it I'm gonna try it anyways and maybe make a friend or two . Anyways, on to my topic:

In a University course I took, my professor always had us create get and set methods with constructors for a given Class (that would be used as an object anyway). Therefore, by second nature, I always create sets and gets when I create a Class for any kind of problem. The problem I get to is when I have a class that contains an array. How would I efficiently create a get and a set for an int[], boolean[], or WhatHaveYou[]?

In a practice program, I created a SalesTeam class, I think I made a constructor and get/sets that works, but I'm really looking for one that is acceptable by convention/standard :



What do you folks think? Am I doing it right?

 
Steve Luke
Bartender
Posts: 4181
22
IntelliJ IDE Java Python
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Welcome to the Ranch!

You aren't doing it wrong, but there are some tweaks to the way you are doing it (depending on how detailed you want to get).

First, the method names: get/setSalaryArray(). it sort of gives away some details about the implementation of the property - that it is an array. The caller doesn't really need to know that it is an array under-the-hood, they just care that you can set and get the values in bulk. So you might change it to get/setSalaries() because you convey the same concept (multi-values) without using the word Array which may confuse your API when you later decide to implement it using a List<Integer> instead of int[].

Along the same lines, you might consider allowing the setSalaries() use varargs. That way the user could pass an array if they have one, a single value, or a series of values:

The getSalaries() method would stay the same, but someone could call the method like:

So it is a bit more flexible.

The next two suggestions are about design, you should think about how you want the class to be used. In a simple case, what you present is fine. But often you want to protect the data that is stored in the class from any code outside the class - you don't want to allow outside code to change values without 'going through official channels' (i.e. calling class methods). In your example, I could do this:

Since you have the same array in the class as outside the class some code could modify the salaries in unpredictable ways and break the data in your class - perhaps doing harm (perhaps intentionally to steal higher salaries). So you might want to better protect that data. One way to do that is to duplicate the array so you store the values in one array that never sees the outside world:

Note that I copied it both in the set and the get method to make sure the array never leaks (you would want to do the same thing for the constructor).

I have also seen 'indexed getter and setter' methods that get or set one particular value in the collection. Their signatures would be:

But they are a bit hard to implement by themselves, as you have to grow the array or have another property which defines the size the array (which creates inter-property dependency which you have to check and maintain). For example, you would need to define a variable for the number of elements in the array, then every time that variable is set you would have to grow the salaryArray to match and every time the setSalary() method is called you would need to make sure the index is in range. There are variations and options, but probably more information than is needed for now (unless you wanted more down this route).
 
Phong Tran
Greenhorn
Posts: 8
Firefox Browser IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Wow awesome!

Thanks for the speedy reply as well as a fully detailed explanation on the topic. I got a lot more than I had bargained for! The array was originally created as a graphical array to chart the increments of how much a sales person is making based on their total sales plus an initial stipend. There are 9 different pay grades based on sales, therefore I had initialized the array to have 9 indices.

But in the case where I could use varargs, wouldn't the program be more susceptible to an ArrayOutOfBounds Exception? Would an ArrayList work better in that case?

As for the protection of data that's stored in the class, I thought the use of set and get methods would automatically protect them, does this not apply to Arrays?

Thanks again,

Phong Tran
 
Balaji Vankadaru
Ranch Hand
Posts: 48
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Varargs serves the Purpose when you have a Method which need to take many arguments of a certain data type.

Varargs need to be implemented as an end argument of the method.

It does not throw Array Index of Bound Exception.

Array Index out of bound is thrown when say you have declared array of size 4 and try to add 5 or 7 or any element which is greater than the size of declared once.

getters and setters are the way to encapsulate your code from direct access of your class from outside. Set leverages you to access trough assign values . Get serves to fetch the value.
 
Steve Luke
Bartender
Posts: 4181
22
IntelliJ IDE Java Python
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Phong Tran wrote:Thanks for the speedy reply as well as a fully detailed explanation on the topic. I got a lot more than I had bargained for! The array was originally created as a graphical array to chart the increments of how much a sales person is making based on their total sales plus an initial stipend. There are 9 different pay grades based on sales, therefore I had initialized the array to have 9 indices.

If you have a fixed size array, that is the size should always be 9, then you might be better off with the indexed approach. If you let the user pass in their own array then that array can be any size, so they could pass in one that is 4 long, and you could get an ArrayIndexOutOfBounds exception. Or they could pass one in that is longer than 9 and not understand why only the first 9 are graphed. So you should either check the length and enforce the size of the of the array (throw exceptions if it isn't exactly nine elements), or use indexed accessors to get at a specific element (throwing an exception if the range is not within range.)


And something similar for the get.

But in the case where I could use varargs, wouldn't the program be more susceptible to an ArrayOutOfBounds Exception? Would an ArrayList work better in that case?

The varargs really are just passed in as an array, so it behaves the same as the original method in practice. It just gives more flexibility in how the method could be called. It is not any more succeptible to the ArrayOutOfBounds exception than the original.

As for the protection of data that's stored in the class, I thought the use of set and get methods would automatically protect them, does this not apply to Arrays?

Keeping the fields private and using setters and getters to provide access to them provides some level of protection. A user couldn't simply change the array the SalesTeam points to, because they don't have access. But with arrays, and all Objects, the calling code gets access to the Object (the array) the field can point to. That means they can change the internal state of the array. The setter can't change how the user can access the internals of the Objects (and arrays) they pass in or get returned from the setters/getters. So the only way to really protect from the value being changed is to make copies so if the caller does change the Objects they have access to it does not affect the Objects you store.

By the way, I just noticed the salaryArray variable in the initial code is public, not private. This sort of destroys the purpose of the setters/getters (and this discussion about protecting data) because the caller could directly assign or retrieve to the variable:



I thought the use of set and get methods would automatically protect them

Accessors give more functionality than just protecting the data members. They allow you to change implementation later on without affecting the callers - example you could decide that it is better to store the salaries as a List later on. You could do so without changing the method calls, but changing the implementation:


Setters also provide the opportunity to validate the data (like I showed in the first snippet with the index). Then there are a lot of other benefits of method use, such as allowing subclasses to inherit or override behavior, perform more complex tasks like storing the data in a data file or database, etc... All that is just implementation detail, while the methods the user calls are exactly the same.
 
Phong Tran
Greenhorn
Posts: 8
Firefox Browser IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That makes sense, I had no idea you can convert an Array into a List, can I also use ArrayList instead?




By the way, I just noticed the salaryArray variable in the initial code is public, not private. This sort of destroys the purpose of the setters/getters (and this discussion about protecting data) because the caller could directly assign or retrieve to the variable:


Yup.. big coding mishap there. Fixing that now -_-" thanks for noticing!
 
Steve Luke
Bartender
Posts: 4181
22
IntelliJ IDE Java Python
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Phong Tran wrote:That makes sense, I had no idea you can convert an Array into a List, can I also use ArrayList instead?


You could do that. But unless you specifically need a method in the ArrayList class that doesn't come in the List interface, I would suggest against it. Using the interface List as a reference allows you to easily substitute other Lists if necessary (for example whatever type is returned by the Collections.synchronizedList() or Collections.unmodifiableList() methods should you need synchronization or want to keep the list from being modified). It is a bit of future-proofing that doesn't cost anything. Note that the actual Object pointed to by the salaryList would still be an ArrayList even if the reference type is List).
 
Winston Gutkowski
Bartender
Posts: 10575
66
Eclipse IDE Hibernate Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Phong Tran wrote:In a University course I took, my professor always had us create get and set methods with constructors for a given Class (that would be used as an object anyway). Therefore, by second nature, I always create sets and gets when I create a Class for any kind of problem...

Well, I think the others here are dealing with your array problem, so I'm going to deal with that statement.

Don't just create getters and setters - especially the latter - willy-nilly. It's lazy programming.

(You said you're in uni, so I'm not being gentle )

Think about what your class needs to do, and expose ONLY those methods that are required to do the job to your clients.

Better still, think about why your class is there, and design your public methods around that behaviour.

If I come into a Library, do I really need to know that it's basically just a big collection of books?
NO.
I'll interact with the Library in pre-defined ways:
  • I'll want to find a book
  • I'll want to take one (or more) out.
  • I'll want to return one (or more).

  • My advice: Spend a bit more time thinking about WHAT your class needs to do; not HOW you're going to do it. That'll give you a much better handle on which methods need to be public, and which don't.

    And personally, I'd say that any class that has public "setters" for individual fields (unless it's a Bean) is probably not very well designed.

    HIH

    Winston
     
    Phong Tran
    Greenhorn
    Posts: 8
    Firefox Browser IntelliJ IDE Java
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Since it still directly pertains to the topic.... I don't think I'm making my class right with the default constructor, the output that I'm getting is NOT what I'm trying to get... can someone help?




    My main class:




    The output that I'm getting is:
    0
    0
    0
    0
    0

    I should be getting:

    6
    7
    8
    9
    10

    Just as the initializer has stated in the Airplane class at the beginning of the post. Why is it not that?

    I'm trying to create an object airplane, with the default values intact (so airplane p1 should have firstClassSeats of 1,2,3,4,5 in its array and economyClassSeats should have 6,7,8,9,10). Yet everything is still zero. :[

    -Phong
     
    Bund De
    Greenhorn
    Posts: 13
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Phong, the first thing you do in your class is initialize your arrays, but then in the no-arg constructor "public Airplane()" you set them to new empty arrays, that's why you're getting all zeros.

    When you say this: "Airplane p1 = new Airplane();", you're saying: "Use the no-arg constructor".
     
    Winston Gutkowski
    Bartender
    Posts: 10575
    66
    Eclipse IDE Hibernate Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Phong Tran wrote:Since it still directly pertains to the topic.... I don't think I'm making my class right with the default constructor, the output that I'm getting is NOT what I'm trying to get... can someone help?

    Well, it would appear that you're initializing your seats in two places: the definition and the constructor.

    Also: why two arrays? It seems to me you could incorporate an awful lot of that logic into a Seat class.

    Winston
     
    Phong Tran
    Greenhorn
    Posts: 8
    Firefox Browser IntelliJ IDE Java
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Winston Gutkowski wrote:
    Phong Tran wrote:Since it still directly pertains to the topic.... I don't think I'm making my class right with the default constructor, the output that I'm getting is NOT what I'm trying to get... can someone help?

    Well, it would appear that you're initializing your seats in two places: the definition and the constructor.

    Also: why two arrays? It seems to me you could incorporate an awful lot of that logic into a Seat class.

    Winston


    That's because the program I'm making only involves the seats themselves. I guess if I wanted to, I would use a Seat class instead of an Airplane class.


    When you say this: "Airplane p1 = new Airplane();", you're saying: "Use the no-arg constructor".


    I did try to use " private int[] firstClassSeats = {1,2,3,4,5};" in the public Airplane() no-arg constructor. It says "Array initializer is not allowed here". So now my question is, is there a way for me to incorporate int[] values into the default constructor?


     
    Henry Wong
    author
    Sheriff
    Posts: 23295
    125
    C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Phong Tran wrote:Hi everyone,

    I'm new to these forums, I always thought it would be cool to contribute as well as take away from this forum but always felt that I didn't have the expertise to put forth my ideas... or have questions that I couldn't get answered by simply Googling. But today I figured, nah forget it I'm gonna try it anyways and maybe make a friend or two . Anyways, on to my topic:

    In a University course I took, my professor always had us create get and set methods with constructors for a given Class (that would be used as an object anyway). Therefore, by second nature, I always create sets and gets when I create a Class for any kind of problem. The problem I get to is when I have a class that contains an array. How would I efficiently create a get and a set for an int[], boolean[], or WhatHaveYou[]?

    In a practice program, I created a SalesTeam class, I think I made a constructor and get/sets that works, but I'm really looking for one that is acceptable by convention/standard :


    Interesting. I am surprised that no one mentioned this yet... Or perhaps someone did, and I missed it.

    JavaBean properties actually defines a standard for array elements -- or specifically, Indexed Properties. If you are looking for a convention/standard, then the JavaBeans standard should be a good one to follow.

    Henry
     
    Darryl Burke
    Bartender
    Posts: 5167
    11
    Java Netbeans IDE Opera
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Phong Tran wrote:I did try to use " private int[] firstClassSeats = {1,2,3,4,5};" in the public Airplane() no-arg constructor.


    A local variable can't be declared private (nor public / protected).
     
    Winston Gutkowski
    Bartender
    Posts: 10575
    66
    Eclipse IDE Hibernate Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Phong Tran wrote:That's because the program I'm making only involves the seats themselves.

    All the more reason to create a Seat class, I would have thought.

    I guess if I wanted to, I would use a Seat class instead of an Airplane class.

    Why should the two be mutually exclusive?

    Seems perfectly reasonable to me that an Airplane might contain Seats.

    Winston
     
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!