considering i have a method which gets a List passed as an param. Within this method i want to use for instance an ArrayList specific function on that list (lets say trimToSize()). What would be the general approach to deal with a problem like this ?
Here two example:
First approach (i don't think this is good)
private void doSomething(final List<T> list) {
// ... do something
((ArrayList<T>) list).trimToSize();
// ... do something
}
Second approach (i think this one is better)
private void doSomething2(final List<T> list) {
final List<T> myList = new ArrayList<T>();
// Collections.copy(myList, list); or
myList.addAll(list);
((ArrayList<T>) myList).trimToSize();
//..do something
}
I'm curious whats the best solution for a problem like this.
Well, the preferred option is to just write the method to take an ArrayList in the first place. If you need ArrayList specific functionality, the method has no business taking a List. Transfer the responsibility of ensuring that the parameter is of the right type to the caller and don't fiddle around with it inside the method.
Why not just declare method as a private void doSomething(final ArrayList<T> list), if you want only ArrayList as parameter?
If you're accepting any object implementing the List interface then your function should only invoke methods implemented from the interface.
If you want to invoke functions from ArrayList class then have ArrayList as your parameter. Much safer than either of your options.
The second we have huge overhead with big lists, but is safer. I would go for the first, but with check whether the provided List is ArrayList and then make a cast.
You should have a strong reasons to not take an ArrayList as a parameter though.
The first option you've shown only works for ArrayLists so it's not an option if you want to support any type of List. If you want to support any type of List you must convert (not cast) it to an ArrayList.
I think there might be some confusion because the List and ArrayList are so closely related (by inheritance). It is only coincidence that the parameter type and the class we need to call the function on are related in this way.
If we abstract the requirements a bit:
We need to act on a series of values
We need to use trimToSize() on the
series of values.
If the values were coming as an array there would be no question but to create a new ArrayList with the values from the array and then use trimToSize(), because casting would not be an option. It is just bad luck that the method we need trimToSize() happens to be on a subclass of List, and the author wants to pass the values as a List.
What about
private void doSomething(final List<T> list) {
final ArrayList<T> arrayList;
if (list instanceof ArrayList) {
arrayList = (ArrayList<T>) list;
} else {
arrayList = new ArrayList<T>(list);
}
...
arrayList.trimToSize();
}
Of course, I agree with Chinmay Kanchi: for a private method, it makes no sense to accept a more general type than necessary. My approach is only feasible if it causes no problems to modify the given list.
Your first method changes the List passed to the method while the other one doesn't. Two methods are not comparable.
Since it is a private method, the convention of using the List interface is not overly important. There is no public API affected so use whichever method is the most convenient for its usage in the class.
For example, if 5 other methods call this method with potentially varying types of List, then use your second option and centralize the conversion in 1 method (you can even throw in a check for type and not convert if you like). If your class only deals with ArrayList internally anyway, and you know that is what it will be when called, then declare it as a ArrayList and make your life easy for yourself.
Related
I have this code
public class TupleSpace implements aTupleSpace {
private Collection<aTuple> theSpace;
public TupleSpace() {
theSpace
}
public void out(aTuple v) {
theSpace.add(v);}
the .add causes an error, I think its either because .add is not defined for a generic collection type? or because im not properly understanding the line:
private Collection<aTuple> theSpace;
i have to keep this line the same but can make any changes to the out method or the rest of the class
I just want to be able to add things to a collection and search the collection for them
A Collection is just an Interface.
It defines what you can do with theSpace and is somewhat independent of what theSpace actually is. It may be a List or a Map or something entirely different.
Collection.add(E e) is indeed a method that is common to all Collections. Still the actual implementation might differ.
However, private Collection<aTuple> theSpace; is just declaring the variable.
It will be set to null when you create an instance of TupleSpace.
This is the reason for the NullPointerException that is thrown when you try to use theSpace.
Hence, you will need to create a concrete Collection instance and assign it to theSpace before you can use it (e.g. add objects).
There are plenty of Collection types that come ready to use with the SDK.
Choose one that fits your use case. Here is an example, using an ArrayList:
// ...
public TupleSpace() {
this.theSpace = new ArrayList<aTuple>();
}
// ...
What is the most correct and/or efficient way in terms of time & memory consumption to write simple pojo class containing ArrayList? (Regarding java mechanism for references, pass by ref', assignments etc.):
public class MyClass {
//1. Do we need to initialize here?
public List<String> mList = new ArrayList<>();
//2. Do we need to declare D. Constructor?
public MyClass() {}
//3. Need to initialize the list here or just pass?
public MyClass(List<String> list) {
this.mList = list;
}
//4. Better way for copy/assignment?
public void setMlist(List<String> list) {
this.mList = list;
}
public List<String> getMList() {
return this.mList;
}
}
Do we need to initialize here?
No, initialize it only when you need it. Make sure to check for null if there is possibility of using it without being initialized.
Do we need to declare D. Constructor?
If you do nothing in it, I don't really see the point of having it. Note that some people prefer to still declare it writing a comment in it and indicate that it should do nothing :
public MyClass(){
//NOP
}
See NOP. This won't change anything related to memory usage. However logically, the default constructor should initialize the list instead of initializing it at the beginning. So we have two options, we pass one that already exists (with the parameterized constructor) or we use the default constructor and create an empty list.
Need to initialize the list here or just pass?
Just pass, else what would be the point of receiving it as an argument ? If you initialize it and re-assign that would make no sense. You may want to check if the received one is null and initialize it otherwise.
Better way for copy/assignment?
If really you want to make a copy, you might want to check Collections#copy. However, this is not the point of setter, what you have done here is correct.
This is impossible to answer without knowing about your intentions. There's a surprisingly large number of design decisions you have to make, even when writing a "simple pojo class containing ArrayList". Here are 8 off the top of my head, but there are many, many more.
Do you want to make the field public or private? (probably private.)
If private, do you want to provide a get method?
Do you want to provide a set method, or do you want the field to be initialized once and for all in the constructor?
Should the argument to your constructor and/or set method only accept a List<String> or will you allow something more general, such as Collection<? extends CharSequence>?
Do you want people using your class to be able to modify mList? (This is different from reassigning mList.)
Do you want to write subclasses, or do you want the class to be final?
If you want to write subclasses, do you want to make any of the methods final?
Do you want to provide a constructor with no argument that initialises the ArrayList to a sensible default value?
The most subtle one of these questions is the 5th. Suppose somebody does this
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
myClass.setMList(list);
and then later does this
System.out.println(myClass.getMList());
They may expect to see [a, b, c], but this may not happen because it is possible to modify the internals of myClass in between. For example:
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
myClass.setMList(list);
list.remove(1); // Modifies the List stored by myClass
System.out.println(myClass.getMList()); // prints [a, c]
If you don't want this kind of thing to be possible you'll have to write a class that copies List objects in the constructor, setter and getter. This will have consequences for performance (but will be tiny for small lists).
There are no right or wrong answers. You need to think through who is using the class, why they need it, and weigh up all the relevant factors when answering all of the above questions.
I have a question about constructing an ArrayList, I have had a Car Class, now I need to make an ArrayList to put content in, I named it as Race, please see code below:
import java.util.ArrayList;
public class Race {
private ArrayList<Car>cars;
public Race(){
cars=new ArrayList<Car>();
}
Now I need to have a method for add content to the ArrayList, there are two ways to write that I am confused with:
First one
public void addCars(){
Car Toyota=new Car("Toyota",1.0,1.0,2.0,2.0);
Car Honda=new Car("Honda",1.0,2.0,1.0,2.0);
Car Mazda=new Car("Mazda",1.0,3.0,2.0,3.0);
Car Suzuki=new Car("Suzuki",1.0,4.0,4.0,2.0);
cars.add(Toyota);
cars.add(Honda);
cars.add(Mazda);
cars.add(Suzuki);
}
Second one
public void addCars(Object nm,String n, double s, double p, double a, double b){
Car name=new Car(n,s,p,a,b);
cars.add(name);
}
Both ways have no mistake reported when I coding, but I am not sure which one is correct, or maybe neither is correct, please help, cheers!
UPDATE:
public void addCars(Car car){
cars.add(car);
}
This is what I used finally, then I created a new class called Test that using main method to add cars individually, but there is mistake in the last line:
public class Test {
public static void main(String[] args) {
Car Toyota=new Car("Toyota",1.0,1.0,2.0,2.0);
**cars.addCars(Toyota);**
I have no idea how to fix it, please help!
It depends on what you want to achieve. In general it is better to provide APIs and use them from the outside. In your case, however, I think your "addCars" function in used to populate your ArrayList(you should call it something like that) - which means to add predefined values to a Collection.
In that case, use the first one.
So, both of your methods are correct (though you should call the first populateCars and the second addCar) and should work, but you need to use them depending on your circumstance.
Also, if you want to provide an API for adding Cars, let the user get a Car object himself, rather than constructing one in the add method. (You might want to change it before adding it, you never know)
So I suggest using either of the methods, but changing the first to:
public void populateCars(){
Car Toyota=new Car("Toyota",1.0,1.0,2.0,2.0);
Car Honda=new Car("Honda",1.0,2.0,1.0,2.0);
Car Mazda=new Car("Mazda",1.0,3.0,2.0,3.0);
Car Suzuki=new Car("Suzuki",1.0,4.0,4.0,2.0);
cars.add(Toyota);
cars.add(Honda);
cars.add(Mazda);
cars.add(Suzuki);
}
or the second to:
public void addCar(Car car){
cars.add(car);
}
Both the ways you mentioned are correct but you should modify the method addCars() to take an argument of type Car .
For example , change the method signature to :
public void addCars(Car car){
cars.add(car);
}
And just pass a new car like this :
addCars(new Car("Toyota",1.0,1.0,2.0,2.0));
The only difference is that in first case you have hard coded elements in the list and in the second approach you add them dynamically. What to use depends on your need.
I suppose you will use the arraylist later on to get elements from it, do sth with them etc. Then you will use getter method on the arraylist, iterate through it and so on... This will work on both approaches you choose.
Both answers are correct. The first method uses a traditional approach to creating objects. The second method is sometimes called a Factory method. Using a factory method is useful when the construction of an object is externally complicated or stamping out multiple objects.
So the answer is: The first approach is correct for objects that are reasonably simple and safe to construct. The second (factory) pattern is better for complex objects.
#pei wang nice question .. Second apporach is gud as ur not hardcoding values .. You should go little bit forward .. please Use DTO design pattern in second approach use setters and getters
Add method expects object type reference for the add method if you pass any reference variable other than object type reference variable then those reference variable upcasted to object type reference.
I have an array with objects inside. How would I use methods on the array element?
My array is of type Object. I tried array[i].getSalary() but this doesn't work.
First of all, you should almost never use an array of Object. The reason is that you lose all type information that :
would make the code more understandable for people who will read your code (including your professor, yourself, and yourself in six months when you will have forgotten everything about the code)
could be used by the compiler and your IDE to tell you when you are doing mistakes even before you test the program.
would avoid the type of error-prone casting that I am going to explain to you in the second part of this answer.
Instead of an array of Object, use an array of the type corresponding to the types of the object that will be put inside it (or a common base class). Assuming that your class is called Employee, you should declare your array this way:
Employee[] employeeArray;
(employeeArray is a better name than array because it tells what kind of objects it contains, again for readability. In general, prefer explicit names for variables.)
With that solution it is easy to use employeeArray[i].getSalary(), if the class Employee contains such method. The intention of this code is also obvious when you read it.
Other possibilities are generic collections like List<Employee> or Set<Employee>, depending on your needs.
If you really have to use an array of Object, and call a getSalary() method, you will have to cast the array elements to the class or interface to which the method getSalary() belongs.
For example and again, if this class is called Employee:
Employee employee = (Employee) array[i];
employee.getSalary();
What casting does is obtaining a reference of type Employee of your object. The object is still the same but now you can call methods of Employee on this object.
But this solution have a number of caveats. First, it is more verbose and it takes two lines to make what could have taken just one. Second, and more importantly, since you have an array of Object, you can not be certain that you really have an object of type Employee, and if it is not the case, the operation will throw a ClassCastException. A solution to this is to first check that the object is really of the desired type:
Object object = array[i];
if (object instanceof Employee) {
Employee employee = (Employee) object;
employee.getSalary();
}
else {
System.err.println("Object is not an Employee: we can not call getSalary()!");
}
But you see that it becomes much more verbose and if you multiply this by the number of times you will have to call a method of these objects, then the code becomes unmanageable.
Do all your objects inside your object[] have the getSalary() method?
If not, then you can obviously see why the compiler doesn't let you do that. There's something funny going on somewhere in your code if you end up in this situation.
If yes, is it either the very same getSalary() method or multiple dynamically bound implementations of the same method in the same class hierarchy?
If neither, you should probably make an interface IHasSalary (lame name, I know) that exposes such a method, make all these objects implement that interface, then declare the array as IHasSalary[].
If yes, find their most specialized common ancestor, say it's the class Employee, and declare the array as Employee[].
I really admire java features and I don't want to give up using it for the next problem:
I have a class that might be inherited, and inside of it is a private ArrayList arr; So the setter function is ok , but the getter function return arr; returns the reference to that variable which anyone capable of editing that whole array which I don't want and private wouldn't make any sense !
In C++ I would just return const arr; and it would return constant reference to the variable.
I so much need the variable not to be cloned or manually copied because there are so many calculations that require to (READ ONLY the variable) WHY there is no const returning in java ???? is there any way I could escape copying ?
p.s (final ArrayList<Integer> arr;) isn't an option cause that array always changes size or element values.
If I couldn't find a fix to that I'm threatening to go back to C++ or make everything public and you should never get my software :D
EDIT: one more important question: Am I asking for something that's not good (Software engineering wise) I mean if JAVA creators thought of not having const reference (returning Read only references) then I must be asking for something that can be handled in other way. or my program design is wrong I'm so confused.
Wrap the return value with java.util.Collections.unmodifiableList. It does not make a copy of the data, but wraps the original list, and delegates read-only operations to the underlying list. Operations which would modify the list are rejected at runtime via UnsupportedOperationException.
Your
return arrayList;
becomes
return Collections.unmodifiableList(arrayList);
Unfortunately the read-only constraints won't be enforced by the compiler. They will, however, be enforced at runtime.
You also have available to you: unmodifiableSet, unmodifiableMap, unmodifiableCollection, unmodifiableSortedSet, and unmodifiableSortedMap. And if these are not enough, you can still take inspiration from this general design approach, and create your own custom read-only wrapper classes.
:) You have several options:
Don't expose getter, provide only methods which are allowed to call, e.g.
public void addToList(Object arg) { this.arr.add(arg);}
Return immutable object:
public List getArr() { return Collections.unmodifiableList(this.arr); }
You could also use Google Guava's immutable collections. In this case, you would store an ImmutableList in your field.
Of course, if your class needs to modify this list internally, using ImmutableList might turn out to be a bad idea, since you'll need to create a new ImmutableList instance and reassign it to the field each time...
But it's perfect when you know the List won't change after object construction.
Immutable example (list won't change after object construction)
#Immutable
public final class Foo {
#Nonnull
private final ImmutableList<String> list;
public Foo(#Nonnull List<String> list) {
// you could also compute the appropriate list here
// before assigning it to the field
this.list = ImmutableList.copyOf(list);
}
public ImmutableList<String> getList() {
return list;
}
}
Mutable example (list may only be modified using the setter)
public class Foo {
#Nonnull
private ImmutableList<String> list = ImmutableList.of();
public ImmutableList<String> getList() {
return list;
}
public void setList(#Nonnull List<String> list) {
this.list = ImmutableList.copyOf(list);
}
}
Remarks
I know it's often advised to make methods return the most generic type possible (List in this case), but I prefer to declare my getter's return type as an ImmutableList, because it acts as documentation (no need to document the returned list's immutability in the Javadoc) and as an API contract. It's like saying "I guarantee this list to be immutable, you do not have to worry or defensively copy it". And it is very concise.
ImmutableList.copyOf() is great, since it automatically rejects null lists (by throwing NullPointerException). It also rejects null elements. And it won't copy the source list if it's already an ImmutableList, which avoids useless object instantiation.
In the second example, I initialize the field to an empty ImmutableList using ImmutableList.of(), because it's a good practice to return empty collections instead of null values (Null Object pattern). You might think that this creates needless object instantiation, but ImmutableList.of() actually returns a singleton.
unmodifiableList is definitely the answer.