Let's say I have this:
public class Whatever {
private ArrayList<String> myList = new ArrayList<String>();
// more code goes here
}
or let's say I have this:
public class Whatever {
private ArrayList<String> myList = null;
public Whatever() {
myList = new ArrayList<String>();
}
}
What's the difference between these two initialisations of myList? Would it be wrong to preffer the first variant?
The first variant will always instantiate the array list, the second one only when calling the default constructor. Meaning for the second solution you will have to call the default constructor for any additional constructor you add e.g.
public class Whatever {
private final List<String> myList;
public Whatever() {
myList = new ArrayList<String>();
}
public Whatever(String name) {
this();
// Other stuff done
}
public Whatever(List<String> myList) {
this.myList = myList;
}
}
The (second) "lazy" initialization method might be better if you don't always use the list (e.g. if you set the list in another constructor directly like in my example) and want to avoid creating unnecessary objects. (EDIT: I changed the ArrayList to an interface and set it final. It wasn't part of the question but it is - as mentioned in the comments - the best way to use List collections).
The JVM first executes code such as this (outside the constructor):
public class Whatever {
private ArrayList<String> myList = new ArrayList<String>();
// more code goes here
}
And only then code such as this (inside the constructor):
public class Whatever {
private ArrayList<String> myList = null;
public Whatever() {
myList = new ArrayList<String>();
}
}
So unless the order of execution is somehow important to you i guess #Daff's answer is the right one.
In this particular example, there is no difference except that the first form is shorter.
However, if the attribute initialization expression (potentially) throws exceptions, the second form allows you to catch the exceptions, or declare them as thrown in the constructor signature.
And of course, if you have multiple constructors, the second form allows you to initialize the attribute differently in each constructor ... or use constructor chaining to initialize the attribute the same ... or mix the two styles of initialization.
Related
I've been asked to do something weird and I need to make a class that is a word set (for a spell checker) and I have to do it using a linked list.
What I've tried for the constructor is this:
public WordSet(LinkedList<String> list) {
LinkedList<String> wordSet = list;
}
But this doesn't let me reference the wordset in the rest of the class. BTW this class doesn't have a main or anything like that
its essentially just a data structure which wraps around a linked list (no I have no idea why they want me to do it).
Can someone tell me what I'm doing wrong here?
As an example of a method in this class, one is:
public void insertWord(String s){
}
where I have to add a word to the wordset, now I know that linked lists have this functionality already
in them but I don't know how to reference a linked list from a constructor because of course the linked list hasn't been instantiated, and can't be because this has no Main() method and I can't just go referencing it from the Class that does have a main method because that's messy.
Create a LinkedinList as a class atribute then try to initialitate it to the constructor so u can after use it when u create an object of the current class
public class WordSet {
private LinkedList<String> list;
public WordSet() {
list = new LinkedList<>();
}
public void insertWord(String s){
list.add(s);
}
What you can do is something like this. First create a class that will have reference variable of your list and then a method for inserting new words. When creating a new object, we want user to "provide" a list on which he/she will work later. Meaning each user will have different list - which is why our constructor has argument of type List.
public class Main {
List<String> words;
public Main(List<String> words) {
this.words = words;
}
public void insertWord(String s){
words.add(s);
}
}
You then create your own list and put that same list inside constructor. Once you have constructed an object, you can insert new words inside your list.
class Test{
public static void main(String[] args) {
List<String> myWords = new LinkedList<>();
myWords.add("table");
myWords.add("window");
myWords.add("car");
Main obj = new Main(myWords);
obj.insertWord("carpet");
//shows all your words
System.out.println(myWords);
}
}
I'm struggling with an assignment of mine and I can't figure out how to add another element to my list.
import java.util.ArrayList;
public class Ballot {
private ArrayList<Candidate> ballot;
private String officeName;
public Ballot(String officeName) {
this.officeName = officeName;
ArrayList<Candidate> ballot = new ArrayList<Candidate>();
}
public String getOfficeName() {
return officeName;
}
public void addCandidate(Candidate c) {
ballot.add(c);
}
public ArrayList<Candidate> getCandidates() {
return ballot;
}
public static void main(String[] args) {
Ballot b = new Ballot("Election");
b.addCandidate(new Candidate("Sarah", "President"));
System.out.println(b);
}
}
When I try to run the document, it throws a NullPointerException. What am I doing wrong?
The constructor initializes a local variable named ballot that hides the data member with the same name. Then, when you try to add to it, it fails with a NullPointerException, since it was never initialized. If you initialize it you should be OK:
public Ballot(String officeName) {
this.officeName = officeName;
ballot = new ArrayList<Candidate>(); // Here!
}
You're not initializing your list of candidates properly in the Ballot constructor. You need to do:
this.ballot = new ArrayList<Candidate>();
Right now you're just creating a local variable named ballot in the constructor which shadows the actual class field. Since it has never been initialized, you end up getting a NullPointerException when you eventually try to add an element to it.
Also, as a best practice, use interfaces instead of the concrete type. This makes it easy to change implementations later. So instead of defining the field as private ArrayList<Candidate> ballot;, define it as private List<Candidate> ballot;.
As simple that you are not using this object. You are never initiliazing your object
Correct way
public Ballot(String officeName) {
this.officeName = officeName;
this.ballot = new ArrayList<Candidate>();
}
You're overriding your class variable with a local variable of the same name. Either initialize the list directly
private List<Candidate> ballot = new Arraylist<>();
or initialize it in the constructor with
ballot = new ArrayList<>();
FYI: You shouldn't assign implementation classes for your local variables and return values if you can help it. "ballot" should just be the List interface as should the getter. That way if you ever want to change the implementation, you don't have to change everything. It could be an ArrayList, LinkedList, Stack, Vector, etc and it won't matter because they're all using the List interface.
is there any way I can declare constructor to take HashSet as one of arguments and then pass HashSet value directly as argument during object initialization?
I mean something like this:
public class Order {
private Set<Product> products = new HashSet<Product>();
public Order (???) {
this.products = ???
}
}
and then, while initializing object:
Order order = new Order("product1", "product2", "product3");
is it possible?
You can use varargs :
public class Order {
private Set<Product> products;
public Order (Product... products) {
this.products = new HashSet<Product> (Arrays.asList(products));
}
}
But then you pass to the constructor Product instances :
Order order = new Order(new Product("product1"), new Product("product2"), new Product("product3"));
I would recommend something like:
public class Order {
private final Set<String> strings;
public Order(final Set<String> strings) {
this.strings = strings;
}
public Order(final String... strings) {
this(toSet(strings));
}
private static Set<String> toSet(String[] strings) {
final Set<String> ss = new HashSet<>();
for (final String s : strings) {
if (!ss.add(s)) {
throw new IllegalArgumentException("Duplicate string " + s);
}
}
return ss;
}
}
This takes a varargs argument, which allows you to invoke the constructor as you would like.
It also checks for duplicates during initialization, I would suggest that duplicates are an error; but you could just log it and carry on.
The above looks to me like you want a constructor taking varargs of String type, and then create the HashSet via those varargs.
A HashSet can't be created via varargs, so perhaps create the set and then add each element in turn. Or create a collection of those vararg elements, and then construct the HashSet directly from that.
If you really need to use the HashSet in the constructor, I would do something like this in the constructor:
public Order (HashSet<String> myHashSet)
Then, whenever you want to initialise it, call it this way:
Order order = new Order(new HashSet<String>(Arrays.asList("product1", "product2")));
It's not very time efficient, but it works.
This class is where I want to call the arrays and set the arrays to empty within the parameters
public class ElectronicsEquipmentSupplier {
private int currentMonth;
private int currentYear;
private String rangeOfProducts;
private CustomerDetailsList details; //Contains the customer details array
private PurchaseOrderList pal; //Contains the purchase array
public ElectronicsEquipmentSupplier(int currentMonth, int currentYear,
String rangeOfProducts ) {
this.currentMonth = currentMonth;
this.currentYear = currentYear;
this.rangeOfProducts = rangeOfProducts;
}
}
This is the class where the array is created. It pulls information from a separate class called PurchaseOrder and then sets the list.
public class PurchaseOrderList {
private ArrayList<PurchaseOrder> purchaseCollection;
public PurchaseOrderList() {
purchaseCollection = new ArrayList<PurchaseOrder>();
}
The CustomerDetailsList class is essentially the same. Just not sure as to the best way to set the array to empty when called in the ElectronicsEquipmentSupplier.
Simply wrap the collection's own clear() method with a publicly-accessible method in your PurchaseOrderClass:
public class PurchaseOrderList {
private ArrayList<PurchaseOrder> purchaseCollection;
public PurchaseOrderList() {
purchaseCollection = new ArrayList<PurchaseOrder>();
}
//THIS IS THE IMPORTANT PART
public void clearPurchaseCollection() {
purchaseCollection.clear();
//You could also accomplish the same thing by reinitializing the list:
//purchaseCollection = new ArrayList<PurchaseOrder>();
}
}
Note however, that calling new PurchaseOrderList() already guarantees an empty purchaseCollection list, since you initialize it in the constructor that way.
So the only time you would need to call clearPurchaseCollection() is if you are reusing this object and want to clean it out first. Depending on the rest of your application, that may be necessary, but it may also just be simpler to throw away that instance and create a new PurchaseOrderList(). Totally depends on the situation.
Is it possible to get the class type from inside the static initialization block?
This is a simplified version of what I currently have::
class Person extends SuperClass {
String firstName;
static{
// This function is on the "SuperClass":
// I'd for this function to be able to get "Person.class" without me
// having to explicitly type it in but "this.class" does not work in
// a static context.
doSomeReflectionStuff(Person.class); // IN "SuperClass"
}
}
This is closer to what I am doing, which is to initialize a data structure that holds information about the object and its annotations, etc... Perhaps I am using the wrong pattern?
public abstract SuperClass{
static void doSomeReflectionStuff( Class<?> classType, List<FieldData> fieldDataList ){
Field[] fields = classType.getDeclaredFields();
for( Field field : fields ){
// Initialize fieldDataList
}
}
}
public abstract class Person {
#SomeAnnotation
String firstName;
// Holds information on each of the fields, I used a Map<String, FieldData>
// in my actual implementation to map strings to the field information, but that
// seemed a little wordy for this example
static List<FieldData> fieldDataList = new List<FieldData>();
static{
// Again, it seems dangerous to have to type in the "Person.class"
// (or Address.class, PhoneNumber.class, etc...) every time.
// Ideally, I'd liken to eliminate all this code from the Sub class
// since now I have to copy and paste it into each Sub class.
doSomeReflectionStuff(Person.class, fieldDataList);
}
}
Edit
I picked the accepted answer based on what applied best to my problem, however it seems to me that all three of the current answers have their merits.
No, it's not possible without grabbing the stacktrace (which is imo nastier than your initial approach and for which I would in any way prefer Thread#getStackTrace() above new Exception()).
Rather do that job in a non-static initializer (or the default constructor) of the abstract class where you check the initialized status.
public abstract class SuperClass {
{
if (!isInitialized(getClass())) {
initialize(getClass());
}
}
}
The called methods in turn can be safely static.
yes, I use this often to initialize a static Log variable :
e.g. :
public class Project implements Serializable, Cloneable, Comparable<Project> {
private static final Logger LOG = LoggerFactory.getLogger(Project.class);
...
To get a class at runtime, you could do something along the lines of
public class Test {
public static void main(String[] args) {
try{
throw new Exception();
}
catch(Exception e){
StackTraceElement[] sTrace = e.getStackTrace();
// sTrace[0] will be always there
String className = sTrace[0].getClassName();
System.out.println(className);
}
}
}
Not pretty but will do the job (ripped from http://www.artima.com/forums/flat.jsp?forum=1&thread=155230).
This means you still make a call from the subclass (so is in the stack trace), but you don't need to include the XXX.class as an argument.