In my continuing education on Arrays and ArrayLists I'm trying to smarten up my code by passing an ArrayList from one method to another. Here is my code:
public void exampleArrayList () {
ArrayList<String> al = new ArrayList<String>();
al.add("AZ");
al.add("BY");
al.add("CX");
al.add("DW");
al.add("EV");
al.add("FU");
al.add("GT");
display(al);
}
public void display(ArrayList al) {
System.out.println("Index of 'AZ': " + al.indexOf("AZ"));
System.out.println("Index of 'FU': " + al.indexOf("FU"));
System.out.println("Index of 'AA': " + al.indexOf("AA"));
System.out.println("Index of 'CX': " + al.indexOf("CX"));
// for (String row : al)
// System.out.println("Value at Index " + al.indexOf(row) +
// " is " + al.get(al.indexOf(row)));
for(int i = 0; i < al.size(); i++)
System.out.println("Value at Index " + al.indexOf(i) +
" is " + al.get(al.indexOf(i)));
}
In the display method works with both for statements commented out. The for statement that is currently commented out doesn't work because row is looking for a String but get's assigned an object even although array al is a string. Do I need to cast al into a string or something? This is not the case when I run the for loop when the loop is in the same method that created the ArrayList in and I don't understand the difference.
The second for statement that isn't commented out causes a crash giving me the following runtime error:
java.lang.ArrayIndexOutOfBoundsException: length=12; index=-1
I tried changing the i < al.size() to a hard coded number and it still failed and I don't know why.
1) You need to pass it as an ArrayList<String>:
public void display(ArrayList<String> al) {
^^^^^^^^
2) You're searching for the integers in the list. The list doesn't contain any integers, so indexOf returns -1. Then you call al.get(-1) where -1 is obviously out of bounds. I'm not sure what you meant to do here.
You are using indexOf(), which, given an int, will search for that int and return its index if the list contains it. As this isn't the case - it is a List<String> - you get index out of bounds because you are trying to retrieve an element at index -1. -1 is returned from indexOf() if the element can't be found, which it can't.
This is why you shouldn't use raw types. Use get() and a List<String> as your parameter (no need to make it specifically ArrayLists):
System.out.println("Value at Index " + i +
" is " + al.get(i));
and
public void display(ArrayList<String> al) {
One other thing to "smarten the code" is to not use the specific implementation in the declaration or parameters.
public void exampleArrayList () {
// use the interface List<T>, not the specific implementation ArrayList<T>
List<String> al = new ArrayList<String>();
...
}
// take the Interface, and give it the type
public void display(List<String> al) {
....
}
The functionality will be the same, but it is a better programming approach to program to interfaces rather than implementations.
EDIT: Also, unless you really need the index for some reason, using the enhance for loop may be more appropriate
for (String s : al) {
//some operation
}
Related
I am trying to create a method which returns a single String (not String array) containing information for all objects in my array list. I know that strings are immutable so I am really struggling with how to add information from each object.
This is my method where I am trying to return a single string:
public String infoForEachItem ()
{
String info;
for (int y =0; y < items.size(); y++)
{
info = "ID: " + items.get(y).getId() + "\n" +
"Name : " + items.get(y).getName() + "\n" +
"Cost: " + items.get(y).getCost() + "\n";
return info;
}
}
As you can see, I want to create a string containing the Id, name, and cost of EACH item as a single string. It won't let me return within a for loop. Is there anyway to append something to the end of String?
StringBuilder
Use StringBuilder to build up text by appending multiple times.
Here is some code expanding on comment by Federico klez Culloca:
public String infoForEachItem ()
{
StringBuilder result = new StringBuilder();
for (Item item : items) {
result.append("ID: ").append(item.getId()).append('\n');
result.append("Name: ").append(item.getName()).append('\n');
result.append("Cost: ").append(item.getCost()).append("\n\n");
}
return result.toString();
}
You can chain the calls to .append as you think it is suitable, and there are overloads of the method for many parameter types.
I have been able to create an object to call a method from a separate class, but I haven't figured out how to use those set/get methods and store them in my current class collection. Help?
Right now, it's storing strings in my class object. I know this is obviously not how it should look but I don't know how to format a proper statement that stores this logic into my foodList ArrayList.
import java.util.ArrayList;
public class GenericStackApp {
public static void main(String[] args) {
// This creates a new ArrayList with String type elements
ArrayList<String> foodList = new ArrayList<>();
// This creates an object, to enable the program to use the methods
// from the other Stack class and keeping this code cleaner
Stack stack = new Stack();
// This calls the addElement method from the Stack class, and passes
// a the String as an argument. I obviously have no issue using
// this external method, the issue for me was actually assigning
// the values of each added element to the existing foodList
// ArrayList I initially created.
stack.addElement("Apples");
stack.addElement("Oranges");
stack.addElement("Bananas");
// This is the code that would be used to display each element, had
// they been added correctly to the foodList ArrayList. Otherwise,
// this is just meaningless code for now.
for (String fruit : foodList) {
System.out.println(foodList);
}
// This provides the actual size of the ArrayList. What's strange to me
// is notice the getSize method is called and returns the size of the
// linkedList
System.out.println("The stack contains " + stack.getSize() + " items.");
// This is code that would have grabbed a peek into the last element
// of the foodList, had they been added to this collection correctly
stack.lastElement();
for (String fruit : foodList) {
System.out.println(foodList);
}
System.out.println("The stack contains " + stack.getSize() + " items.");
// This removes the last element in the list, one by one. The console
// output provides a String summarizing each action.
stack.removeElement();
System.out.println(foodList + " has been removed.");
stack.removeElement();
System.out.println(foodList + " has been removed.");
stack.removeElement();
System.out.println(foodList + " has been removed.");
System.out.println("The stack contains " + stack.getSize() + " items.");
}
}
I expect for the console to output the elements I've added and removed.
public static int menu(String texto, ArrayList<String> opciones) {
for (int i = 0; i < opciones.size(); i++) {
System.out.println((i + 1) + ") " + opciones.get(i));
}
return solicitarNumero(texto + " [1-"
+ opciones.size() + "]", true, 1, opciones.size());
}
I have this method that receives a text (texto) prompting the user to input an option number and an ArrayList with the options.
e.g. {Create entry, remove entry, quit}
solicitarNumero handles the request of the option number and verifies it.
Right now when I'm calling this method using variables of different classes (Franquicia, Gerente, Sistema) I have to go over each ArrayList and create a new one containing that class' toString.
Like so
for (Franquicia franquicia : listaFranquicia) {
listaDatosFranquicia.add(franquicia.toString());
}
Then I use the method with the new ArrayList.
menu("Ingrese el numero de franquicia "
+ "que desea asignar a este control",
listaDatosFranquicia) - 1));
Is there a way I could simply do
menu("Ingrese el numero de franquicia "
+ "que desea asignar a este control",
listaFranquicia) - 1));
Without having to create a new ArrayList?
Yes. Change the method to
public static int menu(String texto, List<?> opciones) {
for (int i = 0; i < opciones.size(); i++) {
System.out.println((i + 1) + ") " + opciones.get(i));
}
return solicitarNumero(texto + " [1-"
+ opciones.size() + "]", true, 1, opciones.size());
}
which is basically equivalent to:
public static int menu(String texto, List<?> opciones) {
for (int i = 0; i < opciones.size(); i++) {
System.out.println((i + 1) + ") " + opciones.get(i).toString());
}
return solicitarNumero(texto + " [1-"
+ opciones.size() + "]", true, 1, opciones.size());
}
unless one of your options is null (in which case the second one will cause a NullPointerException, whereas the first one will print "null").
List<?> means: a list of some unknown type. But since all types extend java.lang.Object, and all you care about is the toString() representation of the objects, you don't really need to know the actual generic type of the list.
Not without changing the method menu.
listaFranquicia is a List<Franquicia> and the method expects a List<String> so you need to convert each Franquicia into a String and make a new list with the result, exactly with the code you have.
It's a bit cumbersome but note that with Java 8, it can be written more simply in a single line:
List<String> listaDatosFranquicia = listaFranquicia.stream()
.map(Franquicia::toString)
.collect(Collectors.toList());
I think a much better signature for your menu method would be
public static int menu(final String texto, final List<?> opciones)
This way you can accept any kind of list of objects, and it will rely on how that instance implements toString() method.
Also note I changed ArrayList to List. It is always better to use the interface instead of the specific implementation when possible.
Java collection
I have two Array list one is lstreminder, and other is lstpresent, there is code below for more specification:
lstintprsnt = new ArrayList<Integer>();
lstreminder = DAORemider.getLatestReminder(u.getName());
if (lstpresent == null || lstpresent.isEmpty()) {
lstpresent = lstreminder;
System.out.println("i m in if" + lstpresent);
} else {
System.out.println("i m in else" + lstpresent.size());
lstreminder.removeAll(lstpresent);
/* at this position listreminder will be empty and do not execute loop,
but still it hold values and executed loo, but if I try this with
an Integer arraylist then its work fine, means it not executed
loop, because it doesnt have any value */
for (Reminder r : lstreminder) {
System.out.println("lst" + r.getReminderid());
lstpresent.add(r);
}
System.out.println("i m in else" + lstpresent);
}
System.out.println("out " + lstpresent);
ServletActionContext.getContext().getSession().put("lstpresent", lstpresent);
lstpresent.clear();
Yes, assignment will just copy the value of lstreminder (which is a reference) to lstpresent . They will both refer to the same object.
Creating a copy is pretty easy though:
List lstpresent = new ArrayList(lstreminder );
I've been trying to get this code to work for what feels like an age at this stage. it is meant to compute prime numbers in a range, and I've written a method to print them. Unfortunately the code will not compile, citing the warning:
"warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.List"
--I understand from googling that this warning is for not declaring what types of values should be in your erray, but I have done this, and the error only seems to come about when I try to use the .add() function on my array list.
and when I try to run it it gives a somewhat more scary error of
"Static Error: Undefined name 'PrimeNumbers'
I think I've gone code-blind at this point and despite several attempts cannot find out what I am doing wrong.
import java.util.*;
public class PrimeNumbers {
private List listOfPrimeNumbers; //add a member variable for the ArrayList
public static void main(String args []){
PrimeNumbers primeNumberList = new PrimeNumbers(50);
primeNumberList.print(); //use our new print method
}
public PrimeNumbers (int initialCapacity) {
listOfPrimeNumbers = new ArrayList<Integer>(initialCapacity/2); //initialCapacity/2 is an easy (if not tight) upper bound
long numberOfPrimes = 0; //Initialises variable numberOfPrimes to 0
int start = 2;
boolean[] isPrimeNumber = new boolean[initialCapacity + 1];
for (int i=0;i==initialCapacity;i++) {//setting all values in array of booleans to true
isPrimeNumber[i] = true;
}
while (start != initialCapacity)
{
if (isPrimeNumber[start])
{
listOfPrimeNumbers.add(start);
//add to array list
numberOfPrimes++;
for (int i = start; start < initialCapacity; i+=start)
{
isPrimeNumber[i] = false;
}
}
start++;
}
}
public void print() //add this printout function
{
int i = 1;
Iterator iterator = listOfPrimeNumbers.listIterator();
while (iterator.hasNext())
{
System.out.println("the " + i + "th prime is: " + iterator.next());
i++;
}
//or just System.out.println(listOfPrimeNumbers);, letting ArrayList's toString do the work. i think it will be in [a,b,c,..,z] format
}
public List getPrimes() {return listOfPrimeNumbers;} //a simple getter isnt a bad idea either, even though we arent using it yet
}
Change this line
private List listOfPrimeNumbers; //add a member variable for the ArrayList
to
private List<Integer> listOfPrimeNumbers; //add a member variable for the ArrayList
This will elimiate the warning.
Bonus - you may want to use the enhanced for loop inside the print method as an alternative approach:
public void print() {
int i = 1;
for (Integer nextPrime:listOfPrimeNumbers) {
System.out.println("the " + i + "th prime is: " + nextPrime);
i++;
}
}
You've decalred primeNumbers to be an untyped List but then created an ArrayList of Integer. Change the declaration of primeNumbers to:
private List<Integer> listOfPrimeNumbers;
The for loop you are using to set all the isPrimeNumber to true doesnt work, the condition should be i<=initialCapacity or even better use:
Arrays.fill(isPrimeNumber, true);
In your print method I wouldnt bother using an iterator and keeping track of the int i, just use a normal for loop.
Without knowing what command you are using to build the code and then try and run it, it is hard to diagnose your runtime error. Make sure your command window is in the same directory as your .class file.