Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
The continuation of the question.
I need to statically and publicly storage data as arrays but I don't want somebody to modify my data. I need only ability to read from those arrays. Therefore I think I should use something like constant arrays which are presented in C++.
As far as I understand Collections.unmodifiableList(Arrays.asList(...)) prevents from modify the list at run-time but not at compile-time.
I've made the following class (code is updated). I suppose I'm not reinventing the wheel because I cannot have the same result using unmodifiableList.
/**
* Emulates constant arrays from C++.
*
* #param <E> Type of elements. Has to be immutable type.
*/
public final class ConstArray<E> {
/** Stores elements. */
private final E[] storage;
/**
* Constructs the object.
*
* #param storage Elements.
*/
public ConstArray(final E[] storage) {
this.storage = storage.clone();
}
/**
* Returns element at {#code idx}.
*
* #param idx Index of returning element.
* #return Element at {#code idx}.
*/
public final E get(final int idx) {
return storage[idx];
}
}
The size method and some other methods are omitted.
I've tested the class and it works.
To paraphrase, if I provide my library and somebody try to modify my data, I think it's better when he/she will know immediately that it's not possible (my class doesn't have a method to modify anything) and if I used unmodifiableList he/she will notice only a crash of the program.
What are advantages and disadvantages of this class? Is there a way to improve this class?
UPD:
I decided to use #Hoopje 's advice (see answers). It's based on experience that I don't have: I'm only a Java beginner.
If "reinventing the wheel" is not disadvantage enough, I see one major disadvantage to your approach:
Arrays.asList and Collections.ummodifiableList return List instances, so they are integrated in the Java Collections framework. This means that you can easily use them in enhanced for loops (for (E item : list) { }), as streams (list.stream()), use all List methods, pass them to methods which expect Collection or List subclasses, etc.
A minor point is that your class makes a copy of the array, whereas both Arrays.asList and Collections.ummodifiableList return views of their argument, so they do not copy the array.
By the way, creating a shallow copy of an array does not require "magic": you can do
this.storage = storage.clone();
Answer to UPD1:
Yes, it is unfortunate that Java does not provide interfaces for collections which cannot be modified. Thus, immutable List instances will have, for example, an add(E) method which simply throws an exception. So there is no compile-time guarantee for immutability.
However, in the Javadoc for your method you will of course write that the returned list is immutable. And if the user of your library tests his/her software, he will very deterministically see the exception and realize that he/she made a programming error.
And believe me, the users of your library will very much hate you if you take away their possibility to use the returned list in Collection-based APIs, just for the small advantage of not having any methods that look as if they would modify it.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I would like to get this inventory_ array from another class.
public class File {
Object[][] inventory=new Object[50][2];
//Reading file to the inventory array.
}
public class Stack {
//I want to copy inventory array to here
}
Lets assume I have 2 different classes and I have 2 different arrays.
public class inventory {
Object[][] inventory_=new Object[50][2];
}
public class bag {
Object[][] bag_=new Object[50][2];
}
So I want to compare inventory_'s items with bag_'s item in the bag class. How can I implement this.
Tehcnically it is possible to have a getter, that just returns the reference to the private Object[][] inventory array.
But this approach considered unsafe, because in this case, external code may change the internal state of your Fileclass via modifying the inventory array state.
For example:
class File {
Object[][] inventory=new Object[50][2];
public Object[][] getInventory() {
return inventory;
}
}
For this case, let's consider this example code:
class Stack {
private File file;
public Stack(File file) {
this.file = file;
}
void processSomething() {
Object[][] stackInventory = file.getInventory();
}
}
And in case you assign something to stackInventory[1][1] (for example), then inventory[1][1] array element into File class instance also will change its value.
And thus it is not considered a good design approach, because it may lead to hard-to-catch bugs in your project.
There are two solutions for this case.
The first one: make defensive copy of the array in your getter.
public Object[][] getInventory() {
Object[][] newInventory = new Object[50][2];
// copy inventory array contents to the newInventory array
return newInventory; // and returning safe copy of the array
}
In this case as you have Object, it is still possible to change internal state of the objects if they are mutable ones.
Either make your objects immutable, or employ deep copy approach upon making defensive copy of the array.
And another way to resolve this issue, which I recommend, is using the Iterator approach.
In your File class make a method that returns the Iterator over your inventory array. And use this iterator in the external code to iterate over the inventory elements.
Or you may make your File class iterable and use foreach operator to process the inventory elements.
Once again, upon designing your approach, keep in mind the mutable/immutable class types. And if it is possible, keep your classes immutable.
Also it is not recommended to name your classes likewise the standard java sdk classes. Your File class could be confused with java.io.File class by someone who will read your code later.
The same goes for your Stack class, which can be confused with java.util.Stack class. Please use other, more descriptive and unique names.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
I'm developing some methods here, some of them needs to have a list as a parameter.
I want to know if the appropriated way to do this is to use a List< T > or use an array [ ].
For example:
void method_name(List< String > arg)
void method_name(String arg[])
Which one is the recommended option?
Can someone help me?
Remember that List<T> is an interface. So passing a List as an argument makes your code more flexible since it does not depend on a specific implementation of a List.
So a method that takes a List<String> as a parameter can actually take an ArrayList<String> or a LinkedList<String> or any other implementation of the List interface. So it could even take a parameter of type MyList<String>, as long as the class MyList declares that it implements the List interface. The benefit of this is that if you wanted to change from using an ArrayList to a LinkedList elsewhere in your code, this method would still work.
By contrast, a method that takes a String[] can only take a String[]. So you would no longer have the benefit of being able to change the way you store these strings elsewhere in your code, without also having to change the method.
In terms of why Google might be using arrays as parameters a lot in their APIs, I think it really comes down to what they are using them for.
So I can't really recommend one or the other. It really depends on what the method does and what you want to do with the collection. For an overview of the key differences between modern programming structures, like Lists, and good old fashioned arrays, take a look at this answer.
There isn't a recommended or standard option. Lists and arrays are not the same object types at all. Both are used throughout Java. You can do either or both (overloading by type).
Keep in mind that there is a third option available namely
void method(String... params)
I can be accessed like an array however the size is flexible and you do not have to put everything into an array before the method call, but simple pass all your Strings.
method(string1, string2, string3);
i think more popular is array parameter.
void method_name(String arg[])
you can get any element from array andunderstand how many elements in array.
I think you should use List. it is slower, but it offers more flexibility and it's easier to use, especially if you are going to resize them.
If your parameter list is fixed just use as many parameters as you need
method(String parameter1, String parameter2)
I find using Arrays is cumbersome. There are several shortcomings:
No generics, see here
you have to copy the whole array into a new bigger one if you want to enhance it
and more depending on what you want to do
Especially when you want to use Lists in your code you have to copy your content all the time. So I'd say to go with List.
method(List<String> parameterList)
There is mentioned another way using variable parameter lists (varargs). However, be aware that you cannot pass the vararg parameter simply into another method using varargs as the vararg parameter is represented as an array and will be passed as such.
method1("first", "second");
void method1(String... params) {
//params[0] will be "first"
//params[1] will be "second"
method2(params);
}
void method2(String... params) {
//params[0] will be an array of Strings
//params[1] will give you an OutOfBoundsException
}
It completely depends on how you are going to use these objects.
Use List when
1) You are going to perform sorting, searching etc but not want to write much lines of code
2) If the size of elements may increase because Lists are resizeable.
Use Array if your requirement is not as above.
I have a class with a private mutable list of data.
I need to expose list items given following conditions:
List should not be modifiable outside;
It should be clear for developers who use getter function that a list they get can not be modified.
Which getter function should be marked as recommended approach? Or can you offer a better solution?
class DataProcessor {
private final ArrayList<String> simpleData = new ArrayList<>();
private final CopyOnWriteArrayList<String> copyData = new CopyOnWriteArrayList<>();
public void modifyData() {
...
}
public Iterable<String> getUnmodifiableIterable() {
return Collections.unmodifiableCollection(simpleData);
}
public Iterator<String> getUnmodifiableIterator() {
return Collections.unmodifiableCollection(simpleData).iterator();
}
public Iterable<String> getCopyIterable() {
return copyData;
}
public Iterator<String> getCopyIterator() {
return copyData.iterator();
}
}
UPD: this question is from a real code-review discussion on the best practice for list getter implementation
The "best" solution actually depends on the intended application patterns (and not so much on "opinions", as suggested by a close-voter). Each possible solution has pros and cons that can be judged objectively (and have to be judged by the developer).
Edit: There already was a question "Should I return a Collection or a Stream?", with an elaborate answers by Brian Goetz. You should consult this answers as well before making any decision. My answer does not refer to streams, but only to different ways of exposing the data as a collection, pointing out the pros, cons and implications of the different approaches.
Returning an iterator
Returning only an Iterator is inconvenient, regardless of further details, e.g. whether it will allow modifications or not. An Iterator alone can not be used in the foreach loop. So clients would have to write
Iterator<String> it = data.getUnmodifiableIterator();
while (it.hasNext()) {
String s = it.next();
process(s);
}
whereas basically all other solutions would allow them to just write
for (String s : data.getUnmodifiableIterable()) {
process(s);
}
Exposing a Collections.unmodifiable... view on the internal data:
You could expose the internal data structure, wrapped into the corresponding Collections.unmodifiable... collection. Any attempt to modify the returned collection will cause an UnsupportedOperationException to be thrown, clearly stating that the client should not modify the data.
One degree of freedom in the design space here is whether or not you hide additional information: When you have a List, you could offer a method
private List<String> internalData;
List<String> getData() {
return Collections.unmodifiableList(internalData);
}
Alternatively, you could be less specific about the type of the internal data:
If the caller should not be able to do indexed access with the List#get(int index) method, then you could change the return type of this method to Collection<String>.
If the caller additionally should not be able to obtain the size of the returned sequence by calling Collection'size(), then you could return an Iterable<String>.
Also consider that, when exposing the less specific interfaces, you later have the choice to change the type of the internal data to be a Set<String>, for example. If you had guaranteed to return a List<String>, then changing this later may cause some headaches.
Exposing a copy of the internal data:
A very simple solution is to just return a copy of the list:
private List<String> internalData;
List<String> getData() {
return new ArrayList<String>(internalData);
}
This may have the drawback of (potentially large and frequent) memory copies, and thus should only be considered when the collection is "small".
Additionally, the caller will be able to modify the list, and he might expect the changes to be reflected in the internal state (which is not the case). This problem could be alleviated by additionally wrapping the new list into a Collections.unmodifiableList.
Exposing a CopyOnWriteArrayList
Exposing a CopyOnWriteArrayList via its Iterator or as an Iterable is probably not a good idea: The caller has the option to modify it via Iterator#remove calls, and you explicitly wanted to avoid this.
The solution of exposing a CopyOnWriteArrayList which is wrapped into a Collections.unmodifiableList may be an option. It may look like a superfluously thick firewall at the first glance, but it definitely could be justified - see the next paragraph.
General considerations
In any case, you should document the behavior religiously. Particularly, you should document that the caller is not supposed to change the returned data in any way (regardless of whether it is possible without causing an exception).
Beyond that, there is an uncomfortable trade-off: You can either be precise in the documentation, or avoid exposing implementation details in the documentation.
Consider the following case:
/**
* Returns the data. The returned list is unmodifiable.
*/
List<String> getData() {
return Collections.unmodifiableList(internalData);
}
The documentation here should in fact also state that...
/* ...
* The returned list is a VIEW on the internal data.
* Changes in the internal data will be visible in
* the returned list.
*/
This may be an important information, considering thread safety and the behavior during iteration. Consider a loop that iterates over the unmodifiable view on the internal data. And consider that in this loop, someone calls a function that causes a modification of the internal data:
for (String s : data.getData()) {
...
data.changeInternalData();
}
This loop will break with a ConcurrentModificationException, because the internal data is modified while it is being iterated over.
The trade-off regarding the documentation here refers to the fact that, once a certain behavior is specified, clients will rely on this behavior. Imagine the client does this:
List<String> list = data.getList();
int oldSize = list.size();
data.insertElementToInternalData();
// Here, the client relies on the fact that he received
// a VIEW on the internal data:
int newSize = list.size();
assertTrue(newSize == oldSize+1);
Things like the ConcurrentModificationException could have been avoided if a true copy of the internal data had been returned, or by using a CopyOnWriteArrayList (each wrapped into a Collections.unmodifiableList). This would be the "safest" solution, in this regard:
The caller can not modify the returned list
The caller can not modify the internal state directly
If the caller modifies the internal state indirectly, then the iteration still works
But one has to think about whether so much "safety" is really required for the respective application case, and how this can be documented in a way that still allows changes to the internal implementation details.
Typically, Iterator is used only with Iterable, for the purpose of for-each loop. It'll be pretty odd to see a non-Iterable type contains a method returning Iterator, and it maybe upsetting to the user that it cannot be used in for-each loop.
So I suggest Iterable in this case. You could even have your class implements Iterable if that makes sense.
If you want to jump on the Java 8 wagon, returning a Stream probably is a more "modern" approach.
By encapsulation rules you had to always return an unmodifiable list, in your case is a design rule, so return the Collections.unmodifiableCollection, and you don't need to name the method as getUnmodifiable, use getter naming convenction and use Javadoc to tell other developer what kind of list you return and why...careless users will be alerted with an exception!!
I encounter many times of similar code:
class AClass{
private Iterable<String> list;
public AClass(Iterable<String> list){ this.list = list; }
...
}
In this code, a reference of Iterable is passed to AClass directly. The end result is equivalent to directly expose list reference to outside. Even if you make AClass.list final, it still allows code from outside AClass to modify the content of the list, which is bad.
To counter this, we will do a defensive copy in the constructor.
However, this kind of code is very common. Besides performance consideration, what's the intension for people to write this kind of code?
I don't see anything wrong with that pattern. If the class represents objects that operate on a list (or an iterable) then it's natural to provide that list to the constructor. If your class can't handle changes to the underlying collection, then it needs to be fixed or documented. Making a copy of the collection is one way to fix that.
Another option is to change the interface so that only immutable collections are allowed:
public AClass(ImmutableList<MyObject> objects) {
this.objects = objects;
...
You would need some kind of ImmutableList-class or interface of course.
Depending on the use and users of your classes you could also avoid making copies by documenting the known "weakness":
/**
* ...
* #param objects list of objects this AClass-object operates on.
* The list should not be modified during the lifetime
* of this object
*/
public AClass(List<MyObject> objects) ...
Simple answer, if it is your own code/small team, it is often just quicker, easier and less memory and CPU intensive to do things this way. Also, some people just don't know any better!
You might want to take a look at the copy constructor for a familiar idiom.
Its always good practice to make a copy, not only because other people can then modify your values, but also for security reasons.
If the code is being used internally as is pointed by other answers it should not be a problem. But if you are exposing as an API then there are two options:
First is to create a defensive copy and then return it
Second would be to create a UnmodifiableCollection and then return it and document the fact that trying to change anything in the collection may result in exception.
But the first option is more preferable.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Collections.emptyList() vs. new instance
I was trying to understand the difference between create a new instance of a list using:
new ArrayList<X>
and
Collections.emptyList();
As I understood, the later returns an immutable list. That means that it is not possible to add,delete, or modify it.
I want to know why one would create and immutable emptyList ? what is the use?
thanks
Being immutable allows for reusable instances.
Collections.emptyList will always return the exact same singleton instance.
This is very efficient.
In addition to that, immutable data can be safely shared between threads, and is guaranteed to avoid weird side-effects due to coding errors. For that reason it makes defensive copies unnecessary, too.
Say you have to return a collection and you don't want to creating a couple of objects each time.
interface Configurable {
List<String> getConfigurationList();
}
// class which doesn't have any configuration
class SimpleConfigurable implements Configurable {
public List<String> getConfigurationList() { return Collections.emptyList(); }
}
Returning an empty collection is often preferable to returning null
I often use empty lists as Null objects: this avoid having to check for null.
I've used Collections.emptyList for methods that return a list but that are called with arguments that don't make sense.
For instance a stream processing application where you want to access different parts of the stream, perhaps based on dates. You query for a time span of items from the stream but if there are no items in that time span you would return an empty list. Throwing an exception wouldn't make any sense since the isn't anything wrong with the query. Returning null also doesn't make much sense because then all the calling code needs to check for null.
Returning an immutable empty list allows the calling code the handle the return value nicely, you don't need to worry about threading issues since an immutable list is inherently thread safe.
To avoid Unwanted NullPointerException.
In your code, you may return a normal "empty" ArrayList instead of returning null. But, in that way, you will keep creating NEW objects (with default capacity of 10) on each execution which is not a memory efficient approach. Instead of that if you return emptyList, the same instance will be returned on every invocation. This way it saves you from unwanted NullPointerException in a more efficient way. Here is the snip from the Javadoc for emptyList:
/**
* Returns the empty list (immutable). This list is serializable.
*
* <p>This example illustrates the type-safe way to obtain an empty list:
* <pre>
* List<String> s = Collections.emptyList();
* </pre>
* Implementation note: Implementations of this method need not
* create a separate <tt>List</tt> object for each call. Using this
* method is likely to have comparable cost to using the like-named
* field. (Unlike this method, the field does not provide type safety.)
*
* #see #EMPTY_LIST
* #since 1.5
*/