ArrayList is a mutable container class, though, so you don't actually need a setter at all: simply have callers call getStringList() and then mutate the ArrayList themselves:
public final class DataHolder {
private final ArrayList<String> stringList = new ArrayList<>();
public ArrayList<String> getStringList() {
return stringList;
}
}
public static void main(String[] args) {
DataHolder data = new DataHolder();
data.getStringList().add("foo");
}
On the other hand, the more common requirement is to prevent callers from being able to mutate internal data structures, so that your class can actually enforce its invariants on its data. ArrayList is always mutable, so if you need to return an ArrayList but you don't want your private state to be modified, you'll need to copy:
public ArrayList<String> getStringList() {
return new ArrayList<String>(stringList);
}
Alternatively, if possible, it's better to widen the return type and then return some other implementation that your class can use to enforce its invariants. For example, if you don't want people to modify your ArrayList using a getter method, you could widen the type from ArrayList<String> to List<String> and use an unmodifiable implementation, for example:
public List<String> getStringList() {
return Collections.unmodifiableList(stringList);
}
On the other hand, for the setter, it depends on how you want to handle the values. Normally a setFoo method replaces the contents of foo, which you can of course do:
public void setStringList(ArrayList<String> stringList) {
this.stringList = stringList;
}
But most likely you want to also widen the type you will accept. For example, you could accept any Collection instead of just an ArrayList:
public void setStringList(Collection<String> strings) {
this.stringList = new ArrayList<>(strings);
}
It may be more useful, however, to instead expose methods to mutate the underlying list in other ways. For example, perhaps you simply want to support adding new items to the list:
public void addString(String string) {
this.stringList.add(string);
}
public void addStrings(Collection<String> strings) {
this.stringList.addAll(strings);
}
If you do decide to expose a setter that replaces the value, you probably want to first check it for correctness. Since your class initializes the ArrayList in an instance initializer, most likely you don't expect it will ever be null. So you should throw an exception if it is:
public void setStringList(List<String> stringList) {
if (stringList == null) {
throw new NullPointerException("stringList must not be null");
}
this.stringList = stringList;
}
Java 7 added a new Objects.requireNonNull method for exactly this purpose.
ArrayList is a mutable container class, though, so you don't actually need a setter at all: simply have callers call getStringList() and then mutate the ArrayList themselves:
public final class DataHolder {
private final ArrayList<String> stringList = new ArrayList<>();
public ArrayList<String> getStringList() {
return stringList;
}
}
public static void main(String[] args) {
DataHolder data = new DataHolder();
data.getStringList().add("foo");
}
On the other hand, the more common requirement is to prevent callers from being able to mutate internal data structures, so that your class can actually enforce its invariants on its data. ArrayList is always mutable, so if you need to return an ArrayList but you don't want your private state to be modified, you'll need to copy:
public ArrayList<String> getStringList() {
return new ArrayList<String>(stringList);
}
Alternatively, if possible, it's better to widen the return type and then return some other implementation that your class can use to enforce its invariants. For example, if you don't want people to modify your ArrayList using a getter method, you could widen the type from ArrayList<String> to List<String> and use an unmodifiable implementation, for example:
public List<String> getStringList() {
return Collections.unmodifiableList(stringList);
}
On the other hand, for the setter, it depends on how you want to handle the values. Normally a setFoo method replaces the contents of foo, which you can of course do:
public void setStringList(ArrayList<String> stringList) {
this.stringList = stringList;
}
But most likely you want to also widen the type you will accept. For example, you could accept any Collection instead of just an ArrayList:
public void setStringList(Collection<String> strings) {
this.stringList = new ArrayList<>(strings);
}
It may be more useful, however, to instead expose methods to mutate the underlying list in other ways. For example, perhaps you simply want to support adding new items to the list:
public void addString(String string) {
this.stringList.add(string);
}
public void addStrings(Collection<String> strings) {
this.stringList.addAll(strings);
}
If you do decide to expose a setter that replaces the value, you probably want to first check it for correctness. Since your class initializes the ArrayList in an instance initializer, most likely you don't expect it will ever be null. So you should throw an exception if it is:
public void setStringList(List<String> stringList) {
if (stringList == null) {
throw new NullPointerException("stringList must not be null");
}
this.stringList = stringList;
}
Java 7 added a new Objects.requireNonNull method for exactly this purpose.
To set the value, you would take an ArrayList<String> passed as a parameter, and you would simply set the ArrayList to the parameter.
Also, note the use of void rather than the ArrayList<String> shown in your question. Commonly, a setter method does not return anything.
public void setStringList(ArrayList<String> stringList)
{
this.stringList = stringList;
}
Example -
import java.util.ArrayList;
import java.util.List;
public class Test {
List<String> list = null;
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public static void main(String[] args) {
Test test = new Test();
List<String> sample = new ArrayList<String>();
sample.add("element 1");
test.setList(sample);
List<String> sample1 = test.getList();
}
}
For better Encapsulation / OO design I would do following
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TestListGetterSetter {
List<String> list = new ArrayList<>();
//Return copy of the list
public List<String> getList() {
return new ArrayList<>(list);
}
// Copy source list into destination list
public void setList(List<String> listToBeSet) {
if (listToBeSet != null)
this.list.addAll(listToBeSet);
}
public static void main(String[] args) {
TestListGetterSetter testListGetterSetter = new TestListGetterSetter();
List<String> clientList = new ArrayList<>(Arrays.asList("foo", "bar", "HiHa"));
testListGetterSetter.setList(clientList);
System.out.println("TestListGetterSetter.list before clientList modification = " + testListGetterSetter.getList());
//Now you can change "clientList" without affecting testListGetterSetter object
clientList.add("1");
System.out.println("clientList modified List = " + clientList);
System.out.println("TestListGetterSetter.list after clientList modification = " + testListGetterSetter.getList());
}
}
It depends on what you are trying to do, in some cases keeping it somewhat immutable is useful, which looks like what you are going for. You can write the methods a bit more concisely like so.
private int[] myArray = {1,2,3,4,5};
private ArrayList<Integer> myArrayList = new ArrayList<Integer>();
public int[] getMyArray()
{
return Arrays.copyOf(myArray, myArray.length);
}
public ArrayList<Integer> getMyArrayList()
{
return new ArrayList<>(myArrayList);
}
public void setMyArray(int[] newArray)
{
this.myArray = Arrays.copyOf(newArray, newArray.length);
}
public void setMyArrayList(ArrayList<Integer> newArrayList)
{
this.myArrayList = new ArrayList<>(newArrayList);
}
there is no harm in implementing getters and setters for arrays or ArrayLists if you deem it necessary.
For arrays, there is a copyOf and copyOfRange methods which you can use to copy an array into a new array rather than doing it yourself.
As for ArrayLists, there is a copy constructor which you can use to construct a new ArrayList containing the elements of the specified collection instead of doing it yourself as well an addAll method to append all of the elements in the specified collection to the end of another list.
as for:
I assume that it would be better to return copies of the Arrays and ArrayLists
again it depends if you deem it necessary to make the array or ArrayList immutable which depend upon certain factors of what you're trying to achieve.
While you can have setters and getter of List type, you should think carefully about their implementation, because most lists are mutable.
For instance, assume that you want to validate that the jobs list is not empty.
public void setJob(List<Employee> jobs) {
if (jobs.isEmpty()) throw new RuntimeException();
this.job = jobs;
}
Now the following code produces an employee without jobs:
Employee e = ...;
e.setJobs(jobs);
jobs.clear();
//the employee now has no jobs :-(
You can avoid this issue by making a defensive copy
public void setJob(List<Employee> j) {
this.job = new ArrayList<>(j);
}
The same applies to the getter. If you implement it as:
public List<Employee> getJobs() {
return this.jobs;
}
you are allowing the caller to modify the private job list without invoking the corresponding setter: myEmployee.getJobs().clear().
In this case, you may return an unmodifiable list instead of returning the inner object.
public List<Employee> getJobs() {
return java.util.Collections.unmodifiableList(this.jobs);
}
Ordinarily for a collection or array you would use addJob, removeJob and getJobs instead of a get/set pair.
A multi-dimensional array is also a 1-dimensional array: int[a][b][c] is really just int[a*b*c], so the problem boils down to, how do you provide access safely? Simply like this:
public class Foo {
private int[] array;
public Foo(int[] array) {
this.array = Arrays.copyOf(array, array.length);
}
/** @return a copy of the array */
public int[] getArray() {
return Arrays.copyOf(array, array.length);
}
}
That's it.
Callers have a safe copy of the array and can use it in the full normal way arrays are used. No need for delegator methods.
What do you think ArrayList does, or Vector before it?
I think the better question is why, at this point, are you exposing that Foo is backed by an array at all? If you're trying to encapsulate it, you don't need to have accessors and setters all over the place. If you're just trying to create a class wrapper around the array, then I would suggest you have an interface, call it IntList or something, and make Foo a concrete implementation that's backed by the list.