What class to use for ArrayList? - java

I just wanted to clarify this question I had for a while for more efficient and 'correct' code.
I gave a class 'Student' with objects in an array list of objects. I have another class called Class which has an array list of references to the very same objects in the Student class.
Should I declare the 'Class' class as
ArrayList<Student> myStudents = new ArrayList<Student>();
or
ArrayList<Class> myStudents = new ArrayList<Class>();
Also another part of the question is I have seen people declare arrayLists as ArrayList<Student> myStudents = new ArrayList<>();
where the second half of the carrots are left empty. What exactly does the difference mean? Does this mean that the array list is not an object of any class?
Thank you so much for your time and help
Cheers

It depends on what you want to store in the list rather than where you are using it. If you're storing Student objects, then you'll use ArrayList<Student>().
The type omitted on the right side is called type inference (added in java 7), which means the type parameter on the right side will be inferred from the type of the assignment variable on the left. It helps to write the code in a cleaner way. For e.g.
Writing below is easier:
List<Some<Type<Another>>> var = new ArrayList<>();
than:
List<Some<Type<Another>>> var = new ArrayList<Some<Type<Another>>>();

Technically, neither.
You would want to do:
List<Student> myStudents = new ArrayList<>();
if you want to create an ArrayList with Student objects and
List<Class> myClasses = new ArrayList<>();
if you want to create an ArrayList with Class objects.
1) Note the variable names.
2) Note that you should always try to code to an interface (the left side is a List, not an ArrayList). This allows much greater flexibility since you're not dependent on the specific implementation of an ArrayList later on. This point is so powerful! You can write method signatures to accept objects of type List and then use an ArrayList, LinkedList or Stack or any class that implements a List. Depending on how you are using your ArrayList later, the Collection interface may be sufficient instead.
The diamond operator allows the compiler to infer the value of the type argument without having to type it all out. It's needed for backward compatibility for older Java versions.
As a general practice for performance optimization, you will also want to supply an initial capacity of an ArrayList if it's possible. So if you know that there are only 5 classes, then you would do:
List<Class> myClasses = new ArrayList<>(5);

Related

When do I need to create new instance of the List?

When do I need to choose one or the other method for lists? What about the resources we use?
List<String> names = new ArrayList<>(something.getList);
List<String> names = something.getList;
Doing this List<String> names = something.getList; assigns another reference to the something.getList object namely names. With the other syntax you get a brand new names object. As for which to use, is it actually a question of what you need, if you need to pass around a list i'd suggest you to use an Immutable List.
This is the preferred way to do things, it means later on you can change the List of names to be of a different implementation of List because List is the interface and ArrayList is the comcrete implementation. Later in life you may want to change this to be a LinkedList or other implementation that uses the List interface.
I would do like this:
List<String> names = new ArrayList<String>(something.getList());

Typed vs. Non-typed ArrayList

What's the difference between using a typed vs. non-typedArrayList in Java?
For example, Using an ArrayList of CustomObject:
Typed:
ArrayList<CustomObject> typedArray = new ArrayList<>();
typedArray.add(new CustomObject);
or non-typed:
ArrayList<> nonTypedArray = new ArrayList<>();
nonTypedArray.add(new CustomObject);
Is there any situation where the latter is preferred? Is there any difference when the ArrayList is holding different datatypes, e.g. an ArrayList of String, Int, etc.?
In the Second Approach, it is not mandatory to add only CustomObject whereas it is in 1st Approach, otherwise, you will get Compilation Error.
ArrayList<CustomObject> typedArray = new ArrayList<>();
typedArray.add(new CustomObject());
This approach is generally preferable as there are no chances of having Class Cast Exception but in second approach there are high chances of that !!
JavaDocs explains it beautifully : Why to prefer Generics
Stronger type checks at compile time.
Elimination of casts.
Enabling programmers to implement generic algorithms.
It's never preferable to use the latter option. I don't think that is even possible. I think you meant:
ArrayList nonTypedArray = new ArrayList();
This syntax is left over from Java 1.4 and earlier. It still compiles for the purposes of backwards compatibility.
Generics was introduced in Java 1.5 which allowed you to specify the types between angled brackets.
It is always preferable to use generics because it is more type-safe.
That is, if you specify
ArrayList<String> typedArray = new ArrayList<String>();
Then you cannot accidentally add an integer to this array list; if you tried to add an integer, the program would not compile.
Of course, Generics ensures type safety at compile time. At runtime ArrayList<String> typedArray = new ArrayList<String>(); becomes ArrayList typedArray = new ArrayList();. This is to maintain backwards compatibility.
What's the difference between using a typed vs. non-typed ArrayList in
Java?
A typed/generic ArrayList is a collection of objects in which the "type" of the object is defined in angled brackets. Generics were introduced in Java 5 to create type-safe collections.
Before Generics the collection was called untyped/raw type collection because there was no way to specify the compiler the type of the collection being created.
The difference between both is to detect type-safe operations at compile time.
In both of your cases, you are adding object(s) of type 'CustomObject' to the ArrayList. There will be no issue while adding elements in the list, as both lists will consider them as typed objects.
Typed:
ArrayList<CustomObject> typedArray = new ArrayList<CustomObject>();
typedArray.add(new CustomObject);
Untyped:
ArrayList<> nonTypedArray = new ArrayList<>();
nonTypedArray.add(new CustomObject);
Is there any situation where the latter is preferred?
I don't think so. As generics are recommended to be used while creating a list to ensure type-safe operations.
Is there any difference when the ArrayList is holding different
datatypes, e.g. an ArrayList of String, Int, etc.?
Surely, there is a reasonable difference. For an untyped list, you will need to add type-cast while fetching elements from a list. As there is a possibility of the compiler throwing a ClassCastException at runtime due to different types of elements.
In runtime, there is absolutely no difference, however in compilation time, using type parameters can save you from a plethora of errors, so it is always preferable to use generics properly.
The only case where raw types are used reasonably is in legacy applications, but even in this case, you try to use typed parameters if you can.
The use of type simplifies your coding removing the need of casting and also stores your data efficiently
https://docs.oracle.com/javase/tutorial/java/generics/why.html
Yeah, I know this is an old post. But I wanted to share an instance where an untyped ArrayList is useful: when you're writing a function that supposed to act on arbitrary element types. For example, suppose you want to make a generic shuffle function that knows how to shuffle an array. Like so:
ArrayList<Die> diceRolls = getGetPossibleDiceRolls();
ArrayList<Card> cardDeck = getPossibleCards();
ArrayList<GirlToDate> blackbook = getBlackbook();
shuffle(diceRolls);
shuffle(cardDeck);
shuffle(blackbook);
.
.
void shuffle(ArrayList array) {
int size = array.size();
for (int i=0; i<size; ++i) {
int r = random.nextInt(size - i) + i;
// Swap
Object t = array.get(i);
array.set(i, array.get(r));
array.set(r, t);
}
}
Some might argue "yeah, but the proper way to do this is to create an interface or subclass of something like a Shuffleable type..." But really?
In Java 1.7 and upwards you should normally use the constructor like this:
ArrayList<MyObject> list = new ArrayList<>();
or else for a more general List object:
List<MyObject> list = new ArrayList<>();
Observe that you only specify the type <MyObject> once, not twice. This makes your code easier to maintain. The <> causes the constructor to return an ArrayList which is already typed to match the field/variable to which it is being assigned - so that no cast will be required in the calling code.
Do not use new ArrayList() as the constructor. This returns an untyped ArrayList which then has to be cast to a type to match the field/variable to which it is being assigned. This means unnecessary type checking and casting and so generally reduces performance.

Getting objects in linked lists vs. arrays in java

Ok so this is probably a very beginner question but...
Right now I have an object called Person with a method on it called setName
I am in my main class and I have declared
List People = new LinkedList();
What I want to do is simply call the setName function of the object in the first position.
I have found that this is very easy to do when working with an array of People. All I would do would be to say
People[0].setName("steve");
But since it is in a linkedlist I am having troubles.
I tried using the "get" method like so...
People.get(0)
but then it doesn't allow me to use my user defined methods so I can't set the name.
What is the best way to get an object out of a linked list and access its methods and instance variables?
thanks in advance
You want to use generics to make it a list of people:
List<Person> People = new LinkedList<Person>();
People.get(0).setName("steve");
Use generics:
List<Person> people = new LinkedList<Person>();
// …
people.get(0).setName("steve");
You should use generics: List<Person>. Then you would be able to use people.get(0).setName(..)
Note that Java naming convention requires your variable to be lowercase.
You dont set which type of objects you store. So you need upcast:
Person person = (Person)People.get(0);
person.setName("steve");
or set type of stored objects:
List<Person> people = new LinkedList<Person>();
LinkedList is only good when you want to iterate quickly over the list, and when you want to quickly get to the first or last element. Also, you need to properly define people as a LinkedList to have access to the linked list methods, and you should type your list, so:
LinkedList<Person> people = new LinkedList<Person>();
people.getFirst().setName();
However, ArrayList is a better general choice, which offers good performance when accessing elements by their index, so:
List<Person> people = new ArrayList<Person>();
then
people.get(0).setName("fred");
If using Java 1.4 or earlier you need to cast it to People class:
((Person)People.get(0)).setName("SomeName");
If using Java 1.5 or later use generics:
List<Person> people = new LinkedList();
You need to define the Linked list as a Person LinkedList:
LinkedList<Person> people = new LinkedList<Person>();
people.get(0).setName("Steve");
Another note(not about the question, just to improve your Java): You use lowercase on the first letter of variable names, because of Java conventions and any subsequent word's first letter are capitalized;
float personsAge = 57.47;
EXPLANATION(Ignore if easily bored):
The LinkedList was not set to store a specific variable type.
Another way to have solved this problem would have been:
LinkedList people = new LinkedList();
Person person = (Person) people.get(0);
person.setName("steve2")
Although you would have to do this to each 'Person' in the people list, defeating the point of the LinkedList.

Regarding arraylist upcasting

In general to decalre the arrayList we can declare as below.
ArrayList Obj = new ArrayList();
This is correct only. But in our code we will not do like this.we do as below
List Obj = new ArrayList();
Why we will do like this? Why Upcasting ?
And While Upcasting we are restricting its functionality. Any specific reason we declare ArrayList or LinkedList like this?
Yes - because unless you need the specific functionality only exposed via the concrete type, it's generally a good idea to refer to the more general type. That way, if you ever decide to use a different implementation, you know that you're not tied to anything specific to the current implementation. You can later change the single statement:
List<String> list = new ArrayList<String>();
to (say)
List<String> list = new LinkedList<String>();
and know that everything will still compile. Of course the behaviour can change in terms of performance, thread safety etc - but that would be the case anyway.
You're also expressing that you don't need any members which are specific to ArrayList<String>, which can be important when reading the code later.
All of this is particularly relevant when it comes to picking the return type and parameter types of methods. The more specific you are about a return type, the less flexibility you have to change the implementation later. The more specific you are about a parameter type, the less flexibility you give your callers.
The point is that ArrayList and LinkedList are both used as lists. Our program logic shouldn't rely on how they store the list, just that they can be used to store items in an ordered way, which can be accessed based on that fact.
It is not upcasting. It is the right way to work. Actually when you are using List it does not matter how is it implemented. It is important that it is list. All method you are using are defined in interface. The same is correct for all other classes. Always try to use interface in the left side of assignment operator and in interfaces you define. In this case it will be easy to change ArrayList to LinkedList. Just change it in one place: replace new ArrayList by new LinkedList and you are done.
Moreover in most cases you even do not need List. if then you only iterate over the elements it is enough to use Collection. Because Collection interface is implemented by both lists and sets. So in future if you will prefer to store your elements in set you will again have to perform only one change.
The definitive answer can be found in
Joshua Bloch's Effective Java, Item 52: Refer to objects by their interfaces.
Its plain and simple - Polymorphism
You program to a more general or abstract class or interface type like List, and Java's polymorphic behavior will be able to automatically find out at runtime what actual definiton the implemented object belongs to. Here List is an interface.
Polymorphism helps in maintenance and refactoring without much hassle. If you know Polymorphism, you will know this.
ArrayList<String> list;
list = new ArrayList<String>(); //possible
list = new LinkedList<String>(); //not possible
LinkedList<String> list;
list = new ArrayList<String>(); //not possible
list = new LinkedList<String>(); //possible
but
List<String> list;
list = new ArrayList<String>(); //possible
list = new LinkedList<String>(); //possible
to increase this possibility u need to practice this actually :P
Example and use with below example :-
public static List<Integer> intList;
public static List<Integer> ArrayListDemo() {
intList = new ArrayList<>();
intList.add(100);
intList.add(200);
intList.add(500);
return intList;
}
public static List<Integer> LinkedListDemo() {
intList = new LinkedList<>();
intList.add(10);
intList.add(20);
intList.add(50);
return intList;
}
public static void main(String[] args) {
System.out.println(ArrayListDemo());
System.out.println(LinkedListDemo());
}
}

Placing a List in the parameters of another List in java

Sorry if the title is unclear, but I wasn't exactly sure how to describe this in that little amount of words. Okay, so suppose we have this declaration:
ArrayList<String> list = new ArrayList<String>();
//add items to list
Set<String> set = new TreeSet<String>(list);
Now, from what I understand, set will receive the data from list and sort them because that's what TreeSets do. However, on the oracle website, I don't see any constructor in the HashSet class that takes a List as a parameter. So, I don't understand why this works if there is no defined constructor to accept a List as a parameter.
TreeSet has a constructor that takes a Collection, and List is a Collection (List extends Collection).
Many classes in the Java collections framework follow the same concept. ArrayList, for instance, also has a constructor that takes a Collection. This makes it easy to copy data between collections.
Take a look at TreeSet(Collection c). This accepts a Collection and ArrayList implements Collection.

Categories