Tablica ArrayList i błąd "nullpointerexception" podczas jej tworzenia

0

Hej, chcę zrobić tablicę arraylist. Ma ona mieć podstawowe metody, dodawanie elementu i usuwanie pierwszej napotkanej pustej listy. Oprócz tego chcę zaimplementować w niej metody hasNext() i next().
Napisałam kod, mam błąd z którym nie mogę sobie poradzić. W konstruktorze wyskakuje mi znany java lang nullpointerexception, w momencie gdy w polu tablicy tworzę arraylistę. Proszę o pomoc w rozwiązaniu tego problemu.

import java.util.*;

public class Tablice {

	List<Integer>[] tab;
	int rozmiar;

	Tablice(int rozmiar) {
		for (int i = 0; i < rozmiar; i++) {
			tab[i] = new ArrayList<Integer>();
		}
	}

	public void dodaj(int wartosc, int index) {
		if (index >= 0 && index < rozmiar) {
			tab[index].add(wartosc);
		}
	}

	public int usun() {
		int x = 0;
		while (tab[x].isEmpty())
			x++;
		int z = tab[x].get(0);
		tab[z].remove(0);
		return z;
	}

	public List<Integer> next() {
		for (int i = 0; i < tab.length; i++) {
			for (int j = 0; j < tab[i].size(); j++) {
				return tab[i];
			}
			return null;
		}
		return null;

	}

	public boolean hasNext() {
		for (int i = 0; i < tab.length; i++) {
			for (int j = 0; j < tab[i].size(); j++) {
				Iterator<Integer> ite = tab[i].iterator();
				if (ite.hasNext() == true)
					return true;

			}
		}
		return false;
	}

}
 
0

Na pierwszy rzut oka:
Beznadziejnie sformatowany kod.

Na drugi rzut oka:</del>
Nigdzie nie inicjujesz pola tab.

0

Kiedy wrzucam do konstruktora:

tab = new ArrayList<Integer>[2]; 

eclipse wyrzuca mi: "Cannot create a generic array of ArrayList<Integer>"
Co z tym zrobić?

0

Spróbuj tak:

tab = new ArrayList<Integer>(2); 
0

Na pewno potrzebujesz tam tablicy? :P

ArrayList<ArrayList<Integer>> tab = new ArrayList<ArrayList<Integer>>();

http://stackoverflow.com/questions/529085/how-to-generic-array-creation

0

Tak, ktoś się uparł na tę tablicę...

0

To może tak:

public class B extends ArrayList<Integer>
{
}
...
B[] tab = new B[2];
for(int i=0;i<2;i++)
{
     ArrayList<Integer> al = new ArrayList<Integer>();
     tab[i] = (B)al;
}
</del>
0

@bogdans nie rozumiem twojego pomysłu, możesz wytłumaczyć?

0

Wycofuję się z tego pomysłu. Ten kod można skompilować, nie można go wykonać. Zajrzyj do linku, który podałem dwa posty wcześniej.
Możesz też tak:

ArrayList[] tab = new ArrayList[2];
for(int i=0;i<2;i++)
{
    tab[i] = new ArrayList<Integer>();
}

ale wtedy w wielu miejscach musisz rzutować

tab[0].add(7); //tu nie musisz
System.out.println(tab[0].get(0)); //tu nie musisz
System.out.println((Integer)tab[0].get(0)+11); //a tu musisz
0

Gdy tak zrobię wyskakuje mi:
ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized;

0

A w czym to przeszkadza?

0

Chwilę mi zajęło, żeby zrozumieć, że w sumie to niczego nie zmienia...
Tak działa:

 
import java.util.*;
 
public class Tablica implements Iterable {
 
        ArrayList<Integer>[] tab;
        int rozmiar;
 
        Tablica(int size) {
                rozmiar = size;
                tab = new ArrayList[size];
                for (int i = 0; i < size; i++) {
                        tab[i] = new ArrayList<Integer>();
                }
        }
 
        public static void main(String[] args) {
                Tablica stefan = new Tablica(3);
                stefan.dodaj(1, 1);
                stefan.dodaj(2, 2);
                stefan.dodaj(3, 3);
        }
 
        public void dodaj(int wartosc, int index) {
                if (index >= 0 && index < rozmiar) {
                        tab[index].add(wartosc);
                }
        }
 
        public int usun() {
                int x = 0;
                for (int i = 0; i < rozmiar; i++) {
                        if (tab[x].isEmpty())
                                x++;
                }
                int z = tab[x].get(0);
                tab[x].remove(0);
 
                return z;
        }
 
        public void next() {
                for (int i = 0; i < tab.length; i++) {
                        for (int j = 0; j < tab[i].size(); j++) {
                                System.out.println(tab[i]);
                        }
                }
 
        }
 
        public boolean hasNext() {
                for (int i = 0; i < tab.length; i++) {
                        for (int j = 0; j < tab[i].size(); j++) {
                                Iterator<Integer> ite = tab[i].iterator();
                                if (ite.hasNext() == true)
                                        return true;
 
                        }
                }
                return false;
        }
 
        @Override
        public Iterator iterator() {
                // TODO Auto-generated method stub
                return null;
        }
 
}

Mam jeszcze jedno pytanie, mianowicie metoda next() która tu mam nie będzie działać prawidłowo. Chcę, żeby "udawała" iterator. Czyli brała współrzędne, zapamiętywała je i przy następnym wywołaniu pokazywała następny punkt. Nie wiem jednak jak podejść do zagadnienia "zapamiętywania". Jakieś wskazówki?

0

Dodatkowe pola w klasie, w których pamiętasz ostatnie współrzędne.

0

po zmodyfikowaniu metody wygladają tak:

int nrTablicy = 0;
	int nrListy = 0;
	int nrTablicy1 = 0;
	int nrListy1 = 0;
public int next() {

		if (hasNext()) {
			if (nrListy != tab[nrTablicy].size()) {
				nrListy++;
				System.out.println("petla 1");
			} else {
				nrListy = 0;
				nrTablicy++;
				System.out.println("petla 2");
			}
		}
		return tab[nrTablicy].get(nrListy);
	}

	public boolean hasNext() {
		if (nrTablicy1 != tab.length
				&& nrListy1 != tab[nrTablicy1].size()) {
			nrTablicy1++;
			nrListy1++;
			return true;
		} else
			return false;
	}

nie wiem czemu, ale w ogóle nie chodzę do pętli w metodzie next() dlaczego?

0

Jakiej pętli?
Co to za pola nrListy/nrTablicy?

1

Wzięłaś sobie za dużo problemów na raz. Po pierwsze Java nie zezwala na tworzenie tablic typów generycznych dlatego new ArrayList<E>[10] nie da się nawet skompilować. Można z tym sobie poradzić tworząc new Object[10] i każdorazowo przy dostępie robiąc konwersję na właściwy typ:
ArrayList<Integer>[] test = (ArrayList<Integer>[])new Object[10];, jednak przy każdej takiej instrukcji otrzymuje się ostrzeżenia Unchecked cast i można je tylko wygasić, jeżeli autor kodu wie co robi. Dlatego generalnie nie miesza się kolekcji Javy z tablicami. Mimo to niemal każda z kolekcji jest wewnętrznie oparta o obiekty tablicowe, ale jest nie to do zrobienia przez nikogo początkującego bo na to trzeba znać Javę przynajmniej dobrze. Dlatego zadanie zrobienia tablicy kolekcji jako zadanie dla początkujących chyba ktoś niezbyt dobrze przemyślał. :)
Można też zamiast tablicy obiektów przydzielić na stercie tablice typów nie generycznych takich jak new ArrayList[10] i jest to alternatywa, która wykorzystałaś. Tak naprawdę nie ma znaczenia jakiego typu elementów jest tablica ponieważ faktycznie każda tablica obiektów jest tablicą referencji do obiektów, a każdy obiekt musi dziedziczyć po klasie Object. Jest to więc tylko kwestia zapisu konwersji typu referencji przy tworzeniu, odczycie i zapisie.
Następna sprawa, to kwestia iteratora. Twoja klasa ma implementować interfejs Iterable, ale Iterable, to obecnie też typ generyczny, a więc powinno to być Iterable<Integer>. Bez względu na to czy użyje się tej wersji parametrycznej, czy wersji Iterable (RAW, bez parametru), czy Iterable<Object>, to każda z nich będzie iterować po po obiektach. I tu jest potrzebne określenie po jakich obiektach. Czy po listach, które są elementami Twojej tablicy (wtedy class Table implements Iterable<ArrayList<Integer>>) czy po elementach tych list, które powinny być obiektami Integer (wtedy class Table implements Iterable<Integer>), czy w ogóle zrobisz sobie problem i napiszesz class Table implements Iterable, co jest równoważne class Table implements Iterable<Object>. I od razu napiszę, że iterowanie po elementach podrzędnych list jest bardzo trudne do zrobienia dla osoby początkującej - nawet w przypadku prostego iteratora.
Jest to do zrobienia pod warunkiem, że nie użyjesz iteratorów list (a każda ma swojego), lecz będziesz iterować wyłącznie po kolejnych elementach kolejnych list. Od razu zapomnij o jakiejkolwiek pętli for w metodach next lub hasNext. Indeksy bieżące muszą być polami klasy obiektu iterującego, czyli musisz stworzyć dwa pola int - indeks bieżącej listy i indeks elementu w bieżącej liście, które będą służyły wyłącznie do obsługi tych dwóch metod. Metoda hasNext musi sprawdzać czy indeks bieżącej listy doszedł do jej końca, a w takim wypadku musi zmienić indeks bieżącej listy na następny, co też musi sprawdzić (czy liczba list nie została przekroczona) oraz kolejny raz sprawdzić czy indeks tej kolejnej listy też doszedł do końca (bo lista może mieć zero elementów). Dlatego w hasNext będzie musiała być pętla bo przecież może być kilka pustych list po sobie. Metoda next też nie będzie banalna bo najpierw musi wyciągnąć obiekt Integer z bieżącej pozycji wskazywanej przez indeks elementów na liście wskazywanej przez bieżący indeks listy, ale na koniec musi zwiększyć indeks obiektu na liście, a jeżeli się skończy, to wyzerować indeks obiektu i zwiększyć indeks listy. I tu znowu trzeba pamiętać, że kolejne listy też mogą być puste więc trzeba w pętli iterować kolejne listy, żeby napotkać na pierwszy element kolejnej niepustej listy. W każdym razie dla początkującego kupa problemów z napisaniem takiej obsługi iteracji.

Co do tego kodu, który widzę, to next nie może być typu void bo musi zwracać element Integer. Następną rzeczą jest to, że jeżeli klasa jest Iterable<X>, to musi mieć metodę Iterator<X> iterator(), która zwróci obiekt iteratora. Ten obiekt musi być zrobiony jako klasa wewnętrzna i klasa tego właśnie obiektu musi mieć dwa pola indeksowe (listy i elementu na niej). Konstruktor takiego iteratora może być pusty bo choć normalnie musiałby wyzerować oba pola indeksów na starcie, to Java robi to z automatu dla każdego z pól klasy. Dlatego jawnego konstruktora klasy implementującej Iterator nie musi być.

Najlepiej byłoby, żebyś obejrzała implementację jakiegoś prostego kontenera, ale kod źródłowy standardowych kolekcji Javy jest tak fatalny i tak nieczytelny, że lepiej tego nie robić bo można się nauczyć złych nawyków.

1 użytkowników online, w tym zalogowanych: 0, gości: 1