An instance of Class A has a private ArrayList. The instance is responsible for maintaining data stored in the arrayList.
private ArrayList<SomeDataStructure> myPrivateArrayList;
However, when other module ask for the data, this instance of Class A will have to pass the data the whoever asks for it, therefore, there is public function in Class A:
public ArrayList<SomeDataStructure> getMyPrivateArrayList ();
My question, how should I implement this function so that I could guarantee that those who get the arrayList through this public function won't be able to modify it (i.e., the return value is read-only)?
Thanks in advance!
I would suggest doing this instead (if you're allowed to in your situation):
private ArrayList<SomeDataStructure> myPrivateArrayList;
public List<SomeDataStructure> getMyPrivateList () {
return Collections.unmodifiableList(myPrivateArrayList)
}
Note that the exposed data structure is of type List instead of ArrayList. I think (generally speaking) the public interface of a class should not return concrete types, but rather should return interfaces. It simplifies tasks such as this one, and also reduces the amount of dependancy that one class has on the implementation of another class.
Instead of return-type ArrayList<SomeDataStructure>, use List<SomeDataStructure>. Then you can use the java.util.Collections.unmodifiableList(...) utility-method to create a read-only view of your list:
public List<SomeDataStructure> getMyPrivateArrayList()
{
return Collections.unmodifiableList(myPrivateArrayList);
}
Another option is to return a copy of your list:
public ArrayList<SomeDataStructure> getMyPrivateArrayList()
{
return new ArrayList<SomeDataStructure>(myPrivateArrayList);
}
(There are some other options as well, but those are the most common approaches.)
But keep in mind that, if SomeDataStructure is mutable, then callers of either of the above can still mutate any of the objects in your list. (That is, they can do something like obj.getMyPrivateArrayList().get(0).setProp(null).)
In your getMyPrivateArrayList () function do the following :
public List<SomeDataStructure> getMyPrivateArrayList(){
return Collections.unmodifiableList(myPrivateArrayList);
}
Collections.unmodifiableList(someList) returns read-only list.
In your calling class if you try to modify the returned list, you will get error on runtime.
eg.
If you do the following
List<SomeDataStructure> readOnlyList=getMyPrivateArrayList();
readOnlyList.add(new SomeDataStructure());
You'll get following error :
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableList.add(Collections.java:1160)
at MainClass.main(MainClass.java:14)
Do you need to get the list? Or can you simply forward some accessors to the list? You could define some public functions like get(index) which simply call the equivalent methods on your list and return the result. This is most likely what you want to do because it gives people access only to the methods you choose, and you dont have to give them the list itself or waste CPU cycles copying the data into "read-only" structures.
Related
For example, some method has the next implementation:
void setExcludedCategories(List<Long> excludedCategories) {
if (excludedCategories.contains(1L)) {
excludedCategories.remove(1L);
}
}
And it's called in the next way:
setExcludedCategories(Array.asList(1L, 2L, 3L));
Of course, it will lead ot an exception java.lang.UnsupportedOperationException when it will try to remove item.
The question: how can I modify this code to be sure that the input parameter excludedCategories supports remove?
UPD:
Thanks for answers. Let's summarize results:
Always create new ArrayList from the input list to be sure it's mutable - a lot of useless memory would be used -> NO.
Catch the UnsupportedOperationException.
Specify in the JavaDoc that a caller mustn't pass an immutable list - anybody read the JavaDoc? When something doesn't work only :)
Don't use Arrays.asList() in a caller's code - that's an option, if you an owner of this code, but anyway you should know if this concrete method allows immutable or not (see 3).
It seems the second variant is the only way to resolve this problem.
How can I modify this code to be sure that the input parameter excludedCategories supports remove?
In the general case, you can't. Given an arbitrary class that implements the List API, you cannot tell (statically or dynamically) if the optional methods are supported.
You can use instanceof tests to check if the class of the list is known to implement the method or to not implement it. For example ArrayList and LinkedList do, but Collections.UnmodifiableList does not. The problem is that your code could encounter list classes that your tests don't cover. (Especially if it is a library that is intended to be reusable in other peoples applications.)
You could also try to test the behavior of previously unknown classes; e.g. create a test instance, try a remove to see what happens, and record the behavior in a Map<Class, Boolean>. There are two problems with this:
You may not be able to (correctly) instantiate the list class to test it.
The behavior could depend on how you instantiate the class (e.g. constructor parameters) or even on the nature of the element you are trying to remove ... though the latter is pushing the boundary of plausibility.
In fact, the only completely reliable approach is to call the method and catch the exception (if it is thrown) each and every time.
In short, you can't know. If an object implements an interface (such as List) you can't know if it will actually do what is expected for all of the methods. For instance Collections.unmodifiableList() returns a List that throws UnsupportedOperationException. It can't be filtered out via the method signature if you want to be able to get other List implementations.
The best you can do is to throw IllegalArgumentException for known subtypes that don't support what you want. And catch UnsupportedOperationException for other types of cases. But really you should javadoc your method with what is required and that it throws IllegalArgumentException in other cases.
That depends somewhat on what you're trying to do. In your posted example for example you could just catch the UnsupportedOperationException and do something else instead.
This assumes that you can assume that non-mutable containers will throw that on every attempt to modify the container and will do so without side effects (that is they are indeed non-mutable).
In other cases where your code has other side effects than trying to modify the container you will have to make sure these doesn't happen before knowing that you can modify the container.
You can catch the exception in an utility class like in the example below (as others mentioned). Bad thing is you have to do insert/delete to test if there will be exception. You can not use instanceof since all Collections.Unmodifiablexxx classes have default access.
CollectionUtils:
import java.util.List;
public class CollectionUtils {
public <T> boolean isUnmodifiableList(List<T> listToCheck) {
T object = listToCheck.get(0);
try {
listToCheck.remove(object);
} catch (UnsupportedOperationException unsupportedOperationException) {
return true;
}
listToCheck.add(0, object);
return false;
}
}
Main:
import java.util.Arrays;
import java.util.List;
public class Main {
private static final CollectionUtils COLLECTION_UTILS = new CollectionUtils();
public static void main(String[] args) {
setExcludedCategories(Arrays.asList(1L, 2L, 3L));
}
private static void setExcludedCategories(List<Long> excludedCategories) {
if (excludedCategories.contains(1L)) {
if(!COLLECTION_UTILS.<Long>isUnmodifiableList(excludedCategories)){
excludedCategories.remove(1L);
}
}
}
}
Arrays.asList(T... a) returns the List<java.util.Arrays.ArrayList<E>> which is an immutable list. To get your code working just wrap the result with java.util.ArrayList<T> like shown below
setExcludedCategories(new ArrayList<Long>(Arrays.asList(1L, 2L, 3L)));
Always create new ArrayList from the input list to be sure it's mutable - a lot of useless memory would be used -> NO.
Thats actually the preferred way to do things. "A lot of useless memory" isn't a lot in most practical situations, certainly not in your cited exampled.
And ignoring that, its the only robust and inutitively understood idiom.
The only workable alternative would be to explicitly change the name of your method (thus communicating its behavior better), form the example you show, name it "removeExcludedCategories" if its meant to modify the argument list (but not an objects state).
Otherwise if it is meant as a bulk-setter, you're out of luck, there is no commonly recognized naming idiom that clearly communicates that the argument collection is directly incorporated into the state of an object (its dangerous also because the objects state can then be altered without the object knowing about it).
Also, only marginally related, I would design not an exclusion list, but an exclusion set. Sets are conceptually better suited (no duplicates) and there are set implementations that have far better runtime complexity for the most commonly asked question: contains().
I have an object and I want to fill its properties inside of a method so, what is more effective, clean or according to any convention, to send the object as parameter (given that what I send is just a reference of the object) to the method or just declare inside the method an auxiliar object of that type, fill it, and return it?
For example, should I do this:
public class DataEntity{
public void setProperty(Type value) {
}
}
public class EntityBuilder {
public configureEntity(DataEntity toConfig){}
}
or this:
public class DataEntity{
public void setProperty(Type value) {
}
}
public class EntityFactory {
public DataEntity createEntity(){}
}
It largely depends on your use case. With the second variant, you always create a new DataEntity object, while with the first variant, users could reuse a single instance of that class.
If the DataEntity objects are rather short-lived, but a lot of them will be created, the garbage collection might get busy cleaning up all the unused objects with the second variant. With the first variant, it's up to the user if they create a new instance every time or not.
The second variant is the more traditional one, and more often to be seen. It is also less error-prone. Consider the situation a user reuses a single instance, but at some point doesn't take care and gives that object to some other method which decides to keep a reference to it. That instance is now modified, and when the other method (or class of that method) looks at the stored reference, all values have changed!
For this reason, I'd suggest to use the second variant by default. The only case when I'd use the first variant is when know you will have millions of calls to createEntity that will create very short-lived objects and you are absolutely sure that none of the code dealing with such a DataEntity object will keep a reference to it. And even then, I'd first try to benchmark it to see if it really is a bottleneck. (Actually, I contribute to a large simulation framework which generates many millions of such simple Data objects, and for us, it was not yet worth the troubles to switch to the first variant as the gains would just be too small, but the chances of errors due to users keeping a reference to such an object too big)
private final Map q;
public Info()
{
this(Collections.EMPTY_MAP);
}
public Info(final Map q)
{
this.qualifiers = new HashMap(q);
}
public Map getQ()
{
return Collections.unmodifiableMap(q);
}
Do I need to use Collections.unmodifiableMap() because I saw from the JAVA Docs of EMPTY_MAP that it is Immutable?
EMPTY_MAP is immutable but you still need to use Collections.unmodifiableMap(q) if Info has been instantiated with a map that is not EMPTY_MAP, using the second constructor...
No. You need to use Collections.unmodifiableMap() if you want to ensure that clients of your class never modify its internal representation - or rather, if you want to ensure that a failure will occur if a client ever tries to do so.
In the case where the internal map q is Collections.EMPTY_MAP then you wouldn't need to wrap it in a call to Collections.unmodifiableMap because it's already unmodifiable. However you have an alternative constructor that creates q as a modifiable Map, and in that case you'd need to protect it before returning it.
You can also simply return a copy of q in which case clients could modify the returned object without modifying your class's internal state nor raising an exception.
I am trying to determine what the best practices would be for an ImmutableList. Below is a simplistic example that will help drive my questions:
Ex:
public ImmutableCollection<Foo> getFooOne(ImmutableList<Foo> fooInput){
//.. do some work
ImmutableList<Foo> fooOther = // something generated during the code
return fooOther;
}
public Collection<Foo> getFooTwo(List<Foo> fooInput){
//.. do some work
List<Foo> fooOther = // something generated during the code
return ImmutableList.copyOf(fooOther);
}
public void doSomethingOne(){
ImmutableCollection<Foo> myFoo = getFooOne(myList);
...
someOtherMethod(myFoo);
}
public void doSomethingTwo(){
Collection<Foo> myFoo = getFooOne(myList);
...
someOtherMethod(myFoo);
}
My Questions:
Which makes the most sense to use in an application? [doSomethingOne and getFooOne] or [doSomethingTwo and fooTwo]? In other words if you know you are using ImmutableCollections does it make sense to keep casting back and forth and doing copyOf(), or just use Immutable everywhere?
These examples are public methods which could imply that other people use them. Would any of these answers change if the methods were private and used internally?
If a user tries to add anything to an immutable List an exception will be thrown. Because they may not be aware of this, wouldn't it make more sense to explicitly return an ImmutableCollection instead of a Collection?
In general, it's wise not to commit to a specific implementation in your declared return type, but we think of the immutable types as an exception. There are a few reasons to declare a return type of Immutable*:
They document that you're returning a snapshot, not a live view.
They document that the caller can't mutate the result.
They document that insertion order is preserved (which may or may not be significant in your use case).
They document that the collection won't contain null.
Someone might want the asList() or reverse() method.
You may save someone a copyOf() call if he wishes to assign to an Immutable* field. (But note that, if he does include copyOf(), it will short-circuit for most immutable inputs, even if you don't declare the return type.)
Basically, I'm just cribbing from https://github.com/google/guava/wiki/TenThingsAboutImmutableCollections, which you may want to check out in its entirety.
If I understood your intentions, the proper way of designing getFooXxx for making an immutable copy of maybe-mutable-list is something like this:
/**
* Returns an <b>immutable copy</b> of input list.
*/
public ImmutableList<Foo> immutableCopyOfFoo(List<Foo> input){
return ImmutableList.copyOf(input);
}
Why?
ImmutableList.copyOf() does it's magic when given list is immutable,
method signature explicitly says what it does,
method returns ImmutableList which is, in fact, an ImmutableCollection but why would you like to hide information about ImmutableList from user? If he wants, he'll write Iterable foo = immutableCopyOfFoo(mutableFoo); instead, but 99% he'll use an ImmtableList,
returning an ImmutableList makes a promise - "I am immutable, and I will blow everything up if you try to change me!"
and last but not least - proposed method is unnecessary in internal use; just use
someOtherMethod(ImmutableList.copyOf(foo));
directly in your code...
You should check #ChrisPovirk's answer (and link to wiki in that answer) to know that i.e. when List<Foo> input contains nulls, you will get nasty NPE on runtime if you try to make an immutable copy...
EDIT answering comment #1:
Collection contract is less strict than List's one; i.e. Collection doesn't guarantee any order of elements ("Some are ordered and others unordered") while List does ("An ordered collection (also known as a sequence)").
If an input is a List it suggests that order is important and therefore output should guarantee the same. Imagine that:
public ImmutableCollection<Foo> immutableCopyOfFoo(List<Foo> input){
return ImmutableSortedSet.copyOf(input, someFancyComparator);
}
It doesn't smell right. If you don't care about order then maybe method signature should be immutableCopyOfFoo(Collection<Foo> input)? But it depends on concrete use case.
public ImmutableCollection<Foo> getFooOne(ImmutableList<Foo> fooInput){
ImmutableList<Foo> fooOther= fooInput;
return ImmutableList.copyOf(fooOther);
}
This makes no sense at all. Why would you ever copy an immutable collection? The whole point of immutability is: it can't be changed, so you might as well re-use it.
public Collection<Foo> getFooTwo(List<Foo> fooInput){
ImmutableList<Foo> fooOther= ImmutableList.copyOf(fooInput);
return ImmutableList.copyOf(fooOther);
}
??? Why do it twice??? This is fine:
public Collection<Foo> getFooTwo(List<Foo> fooInput){
return ImmutableList.copyOf(fooInput);
}
ImmutableList.copyOf(Collection) is smart enough to return ImmutableList unmodified and create a new ImmutableList for everything else.
My usual approach is:
accept List for parameters (so the interface is easier to use for clients)
if performance/memory usage/thread-safety is important, copy the contents of the provided List into a data structure that is optimized for usage by your class
when returning an ImmutableList, ImmutableList should be the return type (because it gives the caller more information about how it can use the returned value)
when returning a mutable implementation of List, List should be the return type, unless something else about the return type is important (thread-safety, as a bad* example)
* It's a bad example because if your return values need to be thread-safe, it probably means something else is wrong with your code.
Replace List/ImmutableList with any of the immutable collection types.
You should always use the standard JRE classes on public interfaces. There are no extra methods on Guava's Immutable... classes so you're not gaining any compile-time safety: any attempts to make changes to those objects will only fail at run-time (but see Bart's comment). You should document in methods that return collections that they're immutable.
You should make defensive copies of lists provided on public methods if you're worried about concurrent modification, but it's OK to specify ImmutableCollection on private method arguments.
In a software development class at my university, the teacher kept mentioning that on a quiz we needed to make sure that a field returned by a getter needed to be "protected." I guess she meant that nothing outside the class should be able to change it. She didn't give much more of an explanation than that.
For instance:
class Foo {
string[] bar = <some array contents>;
public string[] getBar() {
return bar;
}
}
Any code calling getBar would be able to modify the elements in that array. How do you prevent that from happening? I'm assuming that the object itself should be able to modify the array, just not anything outside the object.
This isn't homework help since the quiz is a couple of weeks old. I simply want to understand Java better since my teacher didn't explain very well.
Update: The teacher wouldn't merely allow us to use protected as the access modifier on the field.
You either use a collection and wrap it in Collections.unmodifiable*() or you defensively copy your array, collection or object if its mutable (which arrays always are).
For example:
class Foo {
private String[] bar = <some array contents>;
public String[] getBar() {
return bar == null ? bar : Arrays.copyOf(bar);
}
}
What you have to watch out for is that this is a shallow copy (so is clone). Not sure what your teacher's problem with clone was.
Just to add to one of the previous answers, you want to make sure that with a collection you aren't using the clone() method to achieve what you are trying to achieve here. This creates a shallow copy of the collection only, all object references contained in the collection copy still point to the same objects as in the original, e.g. the objects in the collection copy can still be modified, even though the original collection cannot. Be sure you are making a deep copy of a returned collection if this is what you are trying to do.
I suspect what she meant was that the visibility of the field itself should be protected (or private) so that access only occurs through the getter. In the case of a collection, you may also want to do as #cletus suggests and return a copy of the collection if you don't want it to be modified outside the class. EDIT Based on your edit, she probably meant both.
class Foo {
protected string[] bar = <some array contents>;
public string[] getBar() {
return bar;
}
}
To protect that field from being changed you need to first make it private and don't provide any setter of any other method which changes that field. This way nobody can change the reference of that variable.
If the field is a mutable Object then again its value can be changed. For that you would need to do deep cloning before returning that object.
I'd add to cletus' first suggestion - the easiest way of making bar immutable would be to use a List instead of an array and return it wrapped in an unmodifiableList. That way it's immediately clear to the client of the class that the contents of bar can't be altered - an UnsupportedOperationException is thrown. Messing about with deep cloning will probably be pretty inefficient, depending on the complexity of your objects, and still returns a bunch of mutable objects - it's just that any changes made to those will be ignored by Foo.
class Foo {
private List<String> bar = new ArrayList<String>();
public Collection<String> getBar() {
return Collection.unmodifiableList(bar);
}
}
(Also might be worth noting that with generics in Java 5+, a list behaves much more like an array than it used to).
Please tell the professor that all non-final fields must be private to preserve encapsulation.
Protected allows your subclass or other classes in the same package to modify the field without your class knowing it.
The only class that should touch non-final fields directly is the class that defines them.
(Think about what would happen if you wanted to later fire an event when the field changes... you can only do that if all access is through the setter...)