ArrayList - dodanie obiektu stworzonego obiektu lokalnie zadeklarowanego

0

Witam.
W poniższym kodzie wywala mi wyjątek o wskaźniku null w miejscu dodawania obiektu do tablicy kolekcji. Obiekt ten tworzę lokalnie i dodaję go do pola klasy, więc może to jest błędem? Tylko jak to rozwiązać inaczej?

class Server {
	public ArrayList arrayList = new ArrayList();
	
	public void register(int i) {
		Obiekt o = new Obiekt();
		o.pole = i;
		arrayList.add(o); // !
	}

}

Dzięki.

0
  1. A możesz zamieścić treść błędu?
  2. Piszesz w Javie 1.4 czy nie używasz parametryzacji z jakichś innych powodów?
0

Ten kod jest niezalecany, ale poprawny. Błąd musi być w tych fragmentach kodu, których nie zamieściłeś.

0
// Server.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.StringTokenizer;


public class Server extends Thread {
	
	private ServerSocket serverSocket;
	private ArrayList<Route> routes;
	
	public Server(ServerSocket serverSocket) {
		this.serverSocket = serverSocket;
	}
	
	public boolean register(StringTokenizer Str) throws ParseException{
		// city1;city2;seatsNumber;date
		Route route = new Route();
		route.cityStart = Str.nextToken();
		route.cityDestination = Str.nextToken();
		route.seatsNumber = Integer.parseInt(Str.nextToken());
		route.date = Str.nextToken();
		routes.add(route);
		
		return true;
	}
	
	public void run() {
		while(true){
			try {
				Socket clientSocket = serverSocket.accept();
				//OutputStream output = clientSocket.getOutputStream();
				InputStream input = clientSocket.getInputStream();
				BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(input));
				String line;
				while(true) {
					// X:city1;city2;seatsNumber;date
					line = bufferedReader.readLine();
					StringTokenizer token = new StringTokenizer(line.substring(2), ";");
					switch(line.charAt(0))
					{
					case 'r':
						register(token);
						break;
						
					case 't':
						// TODO 
						break;
						
					case 'o':
						Iterator<Route> iterator = routes.iterator();
						System.out.printf("Trasy:\n");
						while(iterator.hasNext())
						{
							Route r = (Route) iterator.next();
							System.out.printf("%s -> %s, miejsc:%s, %s\n", r.cityStart, r.cityDestination, r.seatsNumber, r.date);
						}
						break;
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			} catch (ParseException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		int numberOfThreads = 5;
		
		try {
			ServerSocket socketServer = new ServerSocket(2354);
			
			for(int i = 0; i < numberOfThreads; i++) {
			Server server = new Server(socketServer);
			server.start();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
	}
	
	

}
// Route.java
import java.util.StringTokenizer;

public class Route {

	public String cityStart;
	public String cityDestination;
	public int seatsNumber;
	public String date;
	
	public StringTokenizer getTokenized() {
		StringTokenizer stringTokenizer = new StringTokenizer(
			cityStart+";"+cityDestination+";"+String.valueOf(seatsNumber)+";"+date);
		
		return stringTokenizer;
	}
}

Odpalam z konsoli telnet localhost 2354. Łączy się z serwerem i rzucam komendę: "r:Warszawa;Poznan;3;14-12-2011" po tym wyskakuje z serwera na konsolę :

Exception in thread "Thread-0" java.lang.NullPointerException
	at Server.register(Server.java:29)
	at Server.run(Server.java:49)
//29:
routes.add(route);
// ...
// 49:
register(token);

Jestem nowy z Javie, więc popełniam wszelkie możliwe błędy :)
To co teraz piszę, to serwer i klient obsługujący dopisywanie, rezerwowanie, wyświetlanie tras - taka jakby tablica z informacjami, że ktoś jedzie i może dać podwózkę.
Tak się jeszcze zastanawiam, gdzie powinienem zamknąć gniazdka metodą close()?

0

Robisz sobie jaja? Przecież to co teraz zamieściłeś i to co zamieściłeś wyżej to są 2 różne kody. Ten wyżej jest poprawny, ten niżej nie. Nie widzę nigdzie w tym powyższym kodzie

new ArrayList<Route>

W efekcie referencja private ArrayList<Route> routes; na nic nie wskazuje i odwołanie się do niej da NullPointerException (co też czyni).
Poza tym:

  1. Używaj kolekcji przez interfejsy a nie przez konkretne klasy, masz wtedy możliwość podmiany kolekcji na inną w jednej linijce (tzn zamiast pisać ArrayList<Route> routes piszesz List<Route>)
  2. Nie używaj iteratora jeśli nie jest ci faktycznie potrzebny (a jest zwykle tylko wtedy kiedy potrzebujesz usuwać z kolekcji w trakcie iterowania). Java ma taki bajer jak foreach
for(Route r : routes)
{
  System.out.printf("%s -> %s, miejsc:%s, %s\n", r.cityStart, r.cityDestination, r.seatsNumber, r.date);
}
0

Dzięki.
Co do kodu, to napisałem ten kawałek kodu w pierwszym poście, żeby wyjaśnić ideę problemu, ale wyszło inaczej.

Zastanawiam się na tym jak to działa. Tworzę lokalnie w funkcji obiekt Route i dodaję go do pola klasy (Listy<Route>). Po wyjściu z funkcji ten obiekt przepada (prędzej czy później) więc w Liście jest jego kopia, czy tylko jest powiązany z obiektem który zniknął?
Program działa, ale może dlatego, że odśmiecacz nie usunął jeszcze obiektu lokalnego Route.

0

Nie nie nie. Tworzysz obiekt za pomocą new, wiec leży na stercie i NIE JEST tracony po wyjściu z funkcji! Jest tracony dopiero kiedy tracisz wszystkie referencje do niego i GC go usunie. W liście przechowujesz referencje do tego obiektu (tak, do tego samego obiektu, nie do jego kopii).

0

Dzięki za wyjaśnienie sprawy. Tworzę dalej, no mam kolejny problem.

W aplikacji klienta mam przycisk, który wysyła do serwera tekst, serwer ma odpowiedzieć i klient ma wyświetlić odpowiedź.
Gdy korzystam z telnetu to wszytko wygląda jak trzeba, ale w moim kliencie coś nie hasa.

W kliencie tworzę obiekt OutputStream output i wysyłam tekst. Rzeczywiście wysyła, bo w serwerze widzę taką informację. Jednak zaraz po tym klient tworzy obiekt InputStream input i BufferedReaderem czytam netLine(), ale w tym miejscu program się zawiesza i nic się nie dzieje.

Tutaj fragment, o którym mówię:

// w ramce:
// ...
JButton btnOdwierzDane = new JButton("Od\u015Bwierz dane");
		btnOdwierzDane.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {

					OutputStream output = client.socket.getOutputStream();
					PrintWriter printWriter = new PrintWriter(output, false);
					printWriter.print("o:\n");
					printWriter.flush();
					
					
					// TODO nie odbiera
					InputStream input = client.socket.getInputStream();
					BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(input));
					
					String line;
					String text = new String("");				
					while((line = bufferedReader.readLine()) != null) {
						text += line;
					}
					textPane.setText(text);
					
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
		});
		btnOdwierzDane.setBounds(227, 273, 158, 23);
		contentPane.add(btnOdwierzDane);
// ...

Piszę w Eclipse, tutaj cały projekt: http://dl.dropbox.com/u/25023639/lab04_01.zip

Zastanawiam się, czy może logicznie coś namieszałem? Wydaje mi się, że właściwie wykorzystuję gniazdka, ale coś musi być źle.

0

A debugger co mówi? Wisisz na readline? a serwer coś wysyła do klienta?

0

Serwer wysyła coś do klienta, bo mam komunikat na telnecie.
Właśnie odpaliłem debuggera i kombinuje.
Leci pętla while, tworzy tak jak należy zmienną text i z niej nie wyskakuje, ale nie ma kolejnych iteracji. Tak to widzę...

Nie mogę zrozumieć też zasady działania gniazdek i bufforów. Bo raz dostałem kilka odpowiedzi naraz.
Jest taka sytuacja:
klient wysyła pytanie

  • serwer robi swoje i odpowiada
  • klient nie czyta odpowiedzi
  • klient wysyła kolejne pytanie
  • serwer odpowiada
  • klient czyta, no i teraz czytając będę miał dwie odpowiedzi serwera? Obiekt socket był stworzony raz na początku i żył przez cały czas.

edycja:
Trochę się zmieniło.

JButton btnOdwierzDane = new JButton("Od\u015Bwierz dane");
		btnOdwierzDane.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					
					InputStream input = client.socket.getInputStream();
					BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(input));
					
					OutputStream output = client.socket.getOutputStream();
					PrintWriter printWriter = new PrintWriter(output, false);
					printWriter.print("o:\n");
					printWriter.flush();
					String line;
					String text = new String("");
					
					boolean ready = false;
					while((ready = bufferedReader.ready()) && (line = bufferedReader.readLine()) != null) {
						text += line+"\n";
					}
					
					if(ready) text += "\n bylo ready\n";
					// TODO
					// ready zawsze false!!, ale bez bufferedReader.ready() nie działa...
					// wyświetla odpowiedzi serera, których nie obsłużyłem wcześniej
					
					textPane.setText("trasy:\n"+text);
					
					
					
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
		});

Z tym sprawdzaniem gotowości bufora dzieje się coś dziwnego (komentarz TODO).
Nie mogę znaleźć jakiegoś łatwego do zrozumienia materiału o gniazdkach, żeby zrozumieć co się tam dzieje.

Pozdrawiam..

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