Why is this allowed:
import java.util.ArrayList;
public class BurgerClass {
private DefaultMenuClass defaultMenu;
ArrayList<String> burgerMenuItems = new ArrayList<String>();
public void displayBurgerMenu() {
burgerMenuItems = defaultMenu.getDefaultBurgerMenu();
for (String burger : burgerMenuItems) {
System.out.println(burger + "\n");
}
}
}
And this isn't:
import java.util.ArrayList;
public class BurgerClass {
private DefaultMenuClass defaultMenu;
ArrayList<String> burgerMenuItems = new ArrayList<String>();
burgerMenuItems = defaultMenu.getDefaultBurgerMenu(); //error here
public void displayBurgerMenu() {
for (String burger : burgerMenuItems) {
System.out.println(burger + "\n");
}
}
}
To answer the specific question, the reason why the first is "allowed" and the second isn't ——
Neither one is "allowed" or "disallowed"
In both cases, as Mureinik says, defaultMenu is never initialized. In the first case it doesn't matter, because displayBurgerMenu() is never called, so you never reach the line burgerMenuItems = defaultMenu.getDefaultBurgerMenu(); which would cause an error.
In the second case you do attempt to call it, at the line you've marked //error here so you get (I assume*) a NullPointerException.
Either way, you need to initialize defaultMenu to be something that is non-null before you attempt to call a method on it.
You need to do something along the lines of
private DefaultMenuClass defaultMenu = new DefaultMenuClass(<some-params?>);
or have some other way to get a DefaultMenuClass object. It's impossible to tell how that should happen given only the code you've presented in the question.
Separately, and not having anything to do with your error, it's pointless to do both
ArrayList<String> burgerMenuItems = new ArrayList<String>();
and then
burgerMenuItems = defaultMenu.getDefaultBurgerMenu();
You initialize burgerMenuItems to an empty ArrayList then you immediately throw that list away by setting burgerMenuItems to the list returned by .getDefaultBurgerMenu() (if there had been no error and something was returned)
* You really should say what error you are getting in your question, and not leave us to assume something.
#Data
#Builder
class BurgerClass {
private DefaultMenuClass defaultMenu;
public void displayBurgerMenu() {
List<String> burgerMenuItems = defaultMenu.getDefaultBurgerMenu();
for (String burger : burgerMenuItems) {
System.out.println(burger + "\n");
}
}
}
#Data
#Builder
class DefaultMenuClass {
List<String> defaultBurgerMenu;
public DefaultMenuClass(List<String> defaultBurgerMenu) {
this.defaultBurgerMenu = defaultBurgerMenu;
}
}
class Main {
public static void main(String[] args) {
BurgerClass obj = BurgerClass.builder().defaultMenu(DefaultMenuClass.builder().defaultBurgerMenu(Arrays.asList(new String[]{"Item1", "Item2"})).build()).build();
obj.displayBurgerMenu();
}
}
As you can able to see in above code,i am initialize all attribute of BurgerClass by providing builder pattern.
Also you can initialize dafaultMenu attributes using constructor. And while creating an instance of BurgerClass pass value of DefaultMenuClass.
public BurgerClass(DefaultMenuClass defaultMenu) {
this.defaultMenu = defaultMenu;
}
Just run above code, you will get an idea.
Related
I am trying to brushup java after a long time.
Any help is much appreciated.
For demonstration I have Animal Class that has an array of innerclass of Organs.
public class Animal
{
String nameOfAnimal;
Organs [] vitalOrgans = new Organs[3];
public Animal()
{
}
public String getNameOfAnimal() {
return nameOfAnimal;
}
public void setNameOfAnimal(String nameOfAnimal) {
this.nameOfAnimal = nameOfAnimal;
}
#Override
public String toString() {
return "Animal{" + "nameOfAnimal=" + nameOfAnimal + "}";
}
class Organs{
String nameOfOrgan;
public String getNameOfOrgan() {
return nameOfOrgan;
}
public void setNameOfOrgan(String nameOfOrgan) {
this.nameOfOrgan = nameOfOrgan;
}
#Override
public String toString() {
return "Organs{" + "nameOfOrgan=" + nameOfOrgan + '}';
}
}
}
Now in driver file when I make call there is no syntactical error but I get "Exception in thread "main" java.lang.NoSuchFieldError: vitalOrgans"
Animal mamal = new Animal();
mamal.setNameOfAnimal("Chimp");
mamal.vitalOrgans[0].setNameOfOrgan("Heart");
System.out.println(mamal.vitalOrgans[0].getNameOfOrgan());
What would be the way to make this (or similar idea) to work.
Thanks.
You would need to initialize the vitalOrgrans with new Organs(). Like:
public Animal() {
for (int i = 0; i < vitalOrgans.length; i++) {
vitalOrgans[i] = new Organs();
}
}
Because when you say :
Organs[] vitalOrgans = new Organs[3];
You are creating an array of 3 null Organs. Hence the null pointer exception, when accessing "vitalOrgans[i].".
Taking the relevant bit of code:
public class Animal
{
//...
Organs [] vitalOrgans = new Organs[3];
//...
}
Since your declaration of vitalOrgans was never given an access modifier (i.e. one of private, public, protected) it took on default access, which means only other classes in the same package can see it. Since your other block of code is not in the same package, it cannot see the field.
A minimally viable modification to just make it work would be to set the access to public:
public class Animal
{
//...
public Organs [] vitalOrgans = new Organs[3];
//...
}
While this works, it's not necessarily the best solution, as if you ever change how vitalOrgans is represented, or need to perform any validation, those edits would have to be done throughout the application. Thus, a better solution (and also, a major stylistic convention in Java for those exact reasons) is to make it (and all your fields, in fact) private and access via methods:
public class Animal {
private String nameOfAnimal;
private Organs[] vitalOrgans = new Organs[3];
//...
public Organs[] getVitalOrgans() {
return vitalOrgans;
}
//Alternative accessor that fetches only one organ.
public Organs getVitalOrgan(int index) {
if(index >= 0 && index < vitalOrgans.length)
return vitalOrgans[index];
else
return null;
}
public void setVitalOrgans(Organs[] vitalOrgans) {
this.vitalOrgans = vitalOrgans
}
//...
}
Your caller could then access Organs via either form of the get method (note, you probably want Organs to be public):
Animal.Organs futureMammalHeart = mamal.getVitalOrgan(0); //Animal.Organs due to Organs being an inner class.
if(futureMammalHeart != null) //Demonstration of null check. Safety first!
futureMammalHeart.setNameOfOrgan("Heart");
Animal.Organs[] mammalianVitalOrgans = mamal.getVitalOrgans();
if(mammalianVitalOrgans != null) //Just in case...
System.out.println(mamal.mammalianVitalOrgans[0].getNameOfOrgan());
Also, as Ari mentioned in his answer, don't forget to initialize the organs in your array, otherwise you will get a NullPointerException!
I've got a method called removeSup which is supposed to remove an object Supplement from a list of supplements.
this is the code for the method:
private static void removeSup(Supplement supToRemove, List<Supplement> listToRemoveFrom) {
Iterator<Supplement> iterator = listToRemoveFrom.iterator();
while(iterator.hasNext()){
if(iterator.next().equals(supToRemove)){
iterator.remove();
}
}
}
there is a class called magazine which defines the list of supplements.
public class Magazine {
private List<Supplement> supList;
public List<Supplement> getSupList() {
return this.supList;
}
public void setSupList(List<Supplement> supList) {
this.supList = supList;
}
public Magazine(Double cost, String _name){
this.supList = new ArrayList<>();
this.weekCost = cost;
this.name = _name;
}
}
the class supplement has the following constructor
public Supplement(String _name, Double _price, String _magName ){
this.name=_name;
this.price=_price;
this.magName = _magName;
}
in the main class client there is a search that the user can do to remove a certain Supplement
private static void searchSup(){
System.out.println("Search for Supplement");
String search = scanner.nextLine();
for (Supplement sup : magazine.getSupList()) {
if (!sup.getSupName().equalsIgnoreCase(search)) {
//do something
}
else{
removeSup(sup,magazine.getSupList());
}
}
}
the main method in the client class is as follows:
private Magazine magazine;
public static void main(String[] args) {
magazine = new Magazine(3.0, "pop");
List<Supplement> startList = new ArrayList<>();
startList.add(new Supplement("Nat Geo", 3.0,"pop"));
startList.add(new Supplement("Discovery", 5.0,"pop"));
startList.add(new Supplement("Health", 6.3,"pop"));
startList.add(new Supplement("IT", 8.3,"pop"));
magazine.setSupList(startList);
searchSup();
}
When I run this program and type any of the added supplements, i get an error
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at Client.searchSup(Client.java:131)
at Client.searchSup(Client.java:140)
at Client.main(Client.java:588)
is it the for loop i am using to search giving me an error? if so how would i go about fixing this?
You generally shouldn't modify a Collection while iterating over it. It's fine to modify elements, but you really shouldn't remove something from a Collection while iterating. See here: http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html. Also, the Javadoc for ConcurrentModificationException may be helpful.
You might try returning a new list with the Supplement removed:
private static List<Supplement> removeSup(Supplement supToRemove, List<Supplement> listToRemoveFrom) {
List<Supplement> filteredSupplements = new ArrayList<Supplement>();
for(Supplement supplement : listToRemoveFrom) {
if(!suppplement.equals(supToRemove)){
filteredSupplements.add(supplement);
}
}
return filteredSupplements;
}
It seams that the "magazine" is local var in the method of main, not accessible to searchSup.Fix it like
private void searchSup(Magazine magazine)
{
//...
}
and more details if you can provide, the codes in Line 131 and 140 will be helpful.
I figured out that the search i was doing was not working with what i wanted to do so i created a method which returns an integer of the Supplement in the list.
private static int indexOfSup(List<Supplement> supSearchList, String nameOfSup) {
for (Supplement sup : supSearchList) {
if (sup.getSupName().equalsIgnoreCase(nameOfSup)) {
return supSearchList.indexOf(sup);
}
}
return -1;
}
i then use this integer to remove from the list.
a simple List.Remove(index) worked fine
Thanks for all the replies.
Basically, i have a class where i have my arrays in, which is like this
public final class DepotDatabase {
private Driver[] arrayDrivers;
public DepotDatabase() {
arrayDrivers = new Driver[4];
arrayDrivers[0] = new Driver(1234, 1234, 0); // sample driver
arrayDrivers[1] = new Driver(4444, 4444, 0); // sample driver
arrayDrivers[2] = new Driver(1337, 1337, 1); // sample manager
arrayDrivers[3] = new Driver(1234, 1234, 0); // sample driver
}
and i want to print this array in another class, i did set up the array in another class
public Driver(int username, int password, int managerCheck) {
this.username = username;
this.password = password;
this.managerCheck = managerCheck;
}
but now i want to be able to print out all the drivers, but in another class which will be called ViewDrivers or something similar
You can create a method inside DepotDatabase to print the array, then create an object from and call print method.
public final class DepotDatabase {
private Driver[] arrayDrivers;
public void printArray() {
for (int i = 0; i < arrayDrivers.length; i++) {
Driver d = arrayDrivers[i];
System.out.println("Username : " + d.getUsername());
System.out.println("Password : " + d.getPassword());
System.out.println(" Manager Check: " + d.getManagerCheck());
}
}
the from the test class you can do:
public void execute() {
DepotDatabase ddb = new DepotDatabase();
ddb.printArray();
}
That's why you'll need to have getters and setters. You should have:
public Driver[] getDrivers() {
return arrayDrivers;
}
and in the other class, you simply call it (and print it or whatever).
Read this tutorial.
If you plan to print your array in another class you show create an accessor to it.
The common pattern for Java is to use "get plus name off attribute", getDrivers() you should also avoid the class name in such geter as it may changed due to application life.
public final class DepotDatabase {
//your code
public Driver[] getDrivers() {
return this.arrayDrivers;
}
}
Next question to answer is a returning the whole array is good idea. When you return it as above you loose control on it. And every one that call that method will be able to change the content of it.
To prevent this you should use so called Defensive copying
public Driver[] getDrivers() {
return Arrays.copyOf(arrayDrivers, arrayDrivers.length);
}
Then person will get an copy of it an will not harm your class.
The issue with this is that consumer of your class will have to call this method every time to get fresh list of cars.
To solve this issue you may want to user the [collection framework] where instead of array you cold define:
List<Driver> drivers new ArrayList<>();
and provide the drivers as [immutable] list
public Iterable<Driver> getDrivers() {
return java.util.Collections.unmodifiableList(drivers);
}
Iterable is an interface, that allow you to obtain an interator the the list consumer of class wold have possibility to traverse it. IF you wan to allow him to check that list contains some driver you can set the return type as Collection
class Storage {
private String items[] = new String[10];
public String[] getItems() {
return Arrays.copyOf(items, items.length);
}
}
class Store {
Storage storage = new Storage();
private void printStorage() {
String[] items = storage.getItems();
for (String item : items) {
}
}
}
I'm trying to create two objects of a Silo class in a SiloManager class, so that I can access both objects' methods. But I can't seem to make the SiloManager constructor work, nor to instance the classes properly. (I'm a beginner in java). Here's my code:
public class GrainSiloManager {
public GrainSilo silo1 = new GrainSilo(100);
public GrainSilo silo2 = new GrainSilo(50);
public GrainSiloManager(GrainSilo silo1, GrainSilo silo2) {
this.silo1 = silo1;
this.silo2 = silo2;
}
private void showStatus() {
System.out.println("The current grain in silo1 is: " + silo1.getGrain());
System.out.println("The current grain in silo2 is: " + silo2.getGrain());
}
}
As I say i'm a beginnger so go easy heh, thanks for any help.
public GrainSilo silo1 = new GrainSilo(100);
public GrainSilo silo2 = new GrainSilo(50);
public GrainSiloManager(GrainSilo silo1, GrainSilo silo2) {
this.silo1 = silo1;
this.silo2 = silo2;
}
This will get compiled as:
public GrainSilo silo1;
public GrainSilo silo2;
public GrainSiloManager(GrainSilo silo1, GrainSilo silo2) {
this.silo1 = new GrainSilo(100);
this.silo2 = new GrainSilo(50);
this.silo1 = silo1;
this.silo2 = silo2;
}
which as you can see makes little to no sense. You're overwriting the object that you make, with the objects passed into the constructor.
Your constructor is going to replace the "public!" silo1 and silo2 objects with whatever is passed in. You could change your constructor like this
public GrainSiloManager() {
super();
}
or the even shorter (but equivalent)
public GrainSiloManager() {
}
And then call it like this
new GrainSiloManager().showStatus();
or you can use your existing approach (which will replace the GrainSoloManager.silo1 and GrainSoloManager.silo2 in your constructor)
GrainSilo silo1 = new GrainSilo(100);
GrainSilo silo2 = new GrainSilo(50);
new GrainSiloManager(silo1, silo2).showStatus();
I have an issue with one of my class. I'm using a "varargs" constructor for unknown number of parameter.
public Groupe(String...nom){
for(String item:nom){
this.nom.add(item.toLowerCase());
}
}
public Groupe(String nom){
String[] list =nom.split(",");
for(String s : list){
this.nom.add(s.toLowerCase());
}
}
The first constructor is called...that's fine, but there is a conflict when passing only ONE parameter with the second contructor. I would like to use the second constructor when passing only one string, and the first if 2 and more parameters.
I'd want to handle this
new Groupe("Foo,Bar");
This is where I call it. I suspect the "error" comes from there
public void reserver(String...nom){
Groupe gr = new Groupe(nom);
passager.add(gr);
}
I don't pass a String, but a Varargs (tab?)...
It should be fine, with the caveat that null can be converted to either String[] or String:
public class Test {
public Test(String single) {
System.out.println("Single");
}
public Test(String... multiple) {
System.out.println("Multiple");
}
public static void main(String[] args) {
new Test("Foo"); // Single
new Test("Foo", "Bar"); // Multiple
new Test(); // Effectively multiple
// new Test(null); // Doesn't compile - ambiguous
new Test((String) null); // Single
}
}
EDIT: Now that you've shown us the calling code, that's definitely the problem:
public void reserver(String...nom){
Groupe gr = new Groupe(nom);
passager.add(gr);
}
Here, the type of nom is String[] - so it will always call the first constructor. You've got an array of strings there - under what circumstances do you want to call the second constructor?
To be honest, given that the two constructors act significantly differently, I would actually make both constructors private, and provide static methods:
public static Groupe fromStringArray(String... nom)
public static Groupe fromCommaSeparatedString(String nom)
Then it will be absolutely clear what you're expecting in each case.
Maybe this can be a solution:
public Groupe(String...nom){
if (nom.length == 1) {
add(nom[0].split(","));
} else {
add(nom);
}
}
private void add(String[] list) {
for(String s : list){
this.nom.add(s.toLowerCase());
}
}
The varargs part can be empty. So you can get what you want with
public Groupe(String nom){
String[] list = nom.split(",");
for(String s : list){
this.nom.add(s.toLowerCase());
}
public Groupe(String nom1, String nom2, String...nom){
this.nom.add(nom1);
this.nom.add(nom2);
for(String item:nom)
this.nom.add(item.toLowerCase());
}
You could also, of course, use one ctor with an if statement on the length of the input array, splitting out cases 0 (not handled with the code above), 1, and > 1.
public class OverloadVarArgs {
public static void main(String... args){
OverloadVarArgs a = new OverloadVarArgs("One Argument");
OverloadVarArgs b = new OverloadVarArgs("Two", "Arguments");
OverloadVarArgs c = new OverloadVarArgs("One, Argument");
}
public OverloadVarArgs(String a){
System.out.println("Constructor 1");
}
public OverloadVarArgs(String... a){
System.out.println("Constructor 2");
}
}
Output:
Constructor 1
Constructor 2
Constructor 1