Iterowanie kolekcji w pętli for

0

Witam

No więc funkcja getBooks zwraca tablicę obiektów , w przypadku gdy instrukcją dla każdego obiektu jest println wszystko pięknie działa i dla każdego z obiektów jest wykonywana funkcja toString() , natomiast gdy kolejną instrukcją jest remove to funkcja jest wywoływana tylko dla pierwszego obiektu, nie rozumiem czemu nie dla każdego kolejno:

for (Book b : bs1.getBooks() ) bs1.remove(b);
0

Bo gdybyś przeczytał dokumentację wiedziałbyś że tak nie wolno? Jeśli chcesz usuwać to musisz explicite użyć iteratora tutaj.

Iterator<Book> it = bs1.getBooks().iterator();
while(it.hasNext()){
  it.next();
  it.remove();
}
0

tylko że , nadrabiam zaległości w wiedzy i powtarzam nie wykonane ćwiczenia z JAVY :

a zadanie wygląda tak że:
to jest kod mojego wykładowcy:

public class TestBook {

  
  public static void main(String[] args) {
    Book b1 = new Book("A", "bbb");
    Book b2 = new Book("B", "ccc");
    Book b3 = new Book("C", "ddd");
    
    Bookshelf bs1 = new Bookshelf("P1", 10);
    Bookshelf bs2 = new Bookshelf("P2", 2);
    
    try {
      bs1.insert(b1);
      bs1.insert(b2);
      bs1.insert(b3);
      
      System.out.println(bs1);
      for (Book b : bs1.getBooks()) System.out.println(b);
      bs2.insert(b1);
    } catch (Exception exc) {
        System.out.println(exc.getMessage());      
    }
    
    try {
      for (Book b : bs1.getBooks() ) bs1.remove(b);
      bs2.insert(b1);
      bs2.insert(b2);
      
      System.out.println(bs2);
      for (Book b : bs2.getBooks()) System.out.println(b);
      
      bs2.insert(b3);
    } catch (Exception exc) {
        System.out.println(exc.getMessage());      
    }
    
    try {
      bs2.remove(b3);
    } catch (Exception exc) {
        System.out.println(exc.getMessage());      
    }
  }

}

A to ma być wynik działania programu , mojim zadaniem jest stworzyć klasę Book i Bookshelf

Półka P1
A bbb
B ccc
C ddd
Nie mogę wstawić książki na półkę (Półka P2) - jest już na półce: Półka P1
Półka P2
A bbb
B ccc
Nie mogę wstawić książki na półkę (Półka P2) - brak miejsca
Nie mogę zdjąć książki z półki (Półka P2) - nie jest na tej półce

Więc nie wiem co jest nie tak, czy powinienem zwracać coś innego jak tablice obiektów Book w funkcji getBooks?
I przy okazji drugie pytanie aby obsłużyć sytuacje wyjątkowe gdy np. NIE MA miejsca na półce powinienem przedefiniować metodę getMessage() ? z klasy Exception .

0

Ja bym w klasie Bookshelf przechowywał kolekcję książek ArrayList<Book> i ją zwracał metodą getBooks().
Co do komunikatów, to rzucaj własnymi wyjątkami.

0

http://docs.oracle.com/javase/tutorial/collections/interfaces/collection.html

Use Iterator instead of the for-each construct when you need to: Remove the current element. The for-each construct hides the iterator, so you cannot call remove. Therefore, the for-each construct is not usable for filtering.

Musisz sprawdzić która kolekcja pozwala na usuwanie elementów w trakcie foreach, gdzieś pewnie dokumentacja o tym wspomina ;]

Co do wyjątków to wystarczy ze tworząc wyjątek przekażesz do niego stringa jako argument i to będzie to co dostaniesz przy getMessage()

0

Nie widzę w tym wszystkim logiki:
To są moje klasy: na pewno jest co wytykać ale skupmy się na zdefiniowanym przeze mnie problemie

  • Kiedy w metodzie remove zmienię zawartość tablicy polka to juz jest źle a kiedy linijkę z polka[i] = null; za komentuje problem znika, trochę to bez sensu (trochę się zdenerwowałem przyznam szczerze ) bo tablica zwraca przez getBooks to inna tablica jak polka , a samego obiektu wysyłanego do funkcji też nie zmieniam, więc wychodzi na to że jak korzystam z fora dla kolekcji to broń boże nie powinienem nic modyfikować , gdziekolwiek ( o zgrozo pomóżcie mi ta irytacja jest straszna )

BOOK:


public class Book {

	private String autor;
	private String tytul;
	public String polka = null;
	
	Book(String autor , String tytul){
		
		this.autor = autor;
		this.tytul = tytul;
		
	}
	
	public String toString(){
		return (autor + " " + tytul);
	}
	
	public boolean equals(Object obj){
		
		if( this == obj) return true;
		if( obj == null) return false;
		if( getClass() != obj.getClass() ) return false;
		Book other = (Book) obj;
		if ( autor != other.autor || tytul != other.tytul ) return false;
		return true;
		
	}

}

BOOKSHELF


public class Bookshelf {

	private String nazwa;
	private int dlugosc;
	int liczbaKsiazek;
	Book[] polka;
	Book[] tmp;
	
	Bookshelf(String nazwa, int dlugosc){
		
		this.nazwa = nazwa;
		this.dlugosc = dlugosc;
		polka = new Book[dlugosc];
		
	}
	
	public void insert(Book ksiazka){
		
		//System.out.println("Wywolanie insert dla polki: " + nazwa);
		
		if( ksiazka.polka != null ){
			System.out.println("Nie mogę wstawić książki na półkę " + nazwa + " - jest już na półce: " + ksiazka.polka);
		}
		else{
			for(int i = 0 ; i < dlugosc ; i++){
				if( polka[i] == null ){
					polka[i] = ksiazka;
					ksiazka.polka = nazwa;
					liczbaKsiazek++;
					break;
				}
				if( (polka[i] != null) && (i == (dlugosc-1) ) ){
					System.out.println("Nie mogę wstawić książki na półkę (Półka " + nazwa + " - brak miejsca");
				}
			}
		}
		
	}
	
    public Book[] getBooks(){
    	
    	tmp = new Book[liczbaKsiazek];
    	int itmp = 0;
    	
    	for(int i = 0 ; i < dlugosc ; i++){
    		if(polka[i] != null){
    			tmp[itmp] = polka[i];
    			itmp++;
    		}
    	}
    	
		return tmp;
    	
    }

	public void remove(Book ksiazka) {
		
		System.out.println("Wywolanie remove dla polki: " + nazwa);
		
		if(ksiazka.polka == nazwa){
			for(int i = 0 ; i < dlugosc ; i++){
				if( polka[i].equals(ksiazka) ){
					System.out.println("Usunieto: "+ polka[i] +" z: " + nazwa);
					
					polka[i].polka = null;
				    polka[i] = null;
					
					liczbaKsiazek--;
					break;
				}
			}
		}
		else{
			System.out.println("Nie mogę zdjąć książki z półki " + nazwa + " - nie jest na tej półce");
		}
		
	}
	
	public String toString(){
		return ("Polka "+ nazwa);
		
	}
	

}

0

Z tablicą to na pewno nie zadziała. Możliwe że zadziała dla LinkedList<T> na przykład i spróbowałbym właśnie dla takiej kolekcji.

0

No ale ja przecież nie modyfikuje tablicy z fora ani obiektow z tej tablicy

1
import java.util.concurrent.CopyOnWriteArrayList;

public class Bookshelf extends CopyOnWriteArrayList<Book> {
    private static final long serialVersionUID = 1L;
    private final String name;
    private final int maxSize;

    public Bookshelf(String string, int i) {
        name = string;
        maxSize = i;
    }

    public void insert(Book b1) throws Exception {
        if (b1.getAssignedBookshelf() != null) {
            throw new Exception("Nie mogę wstawić książki na półkę (" + this + ") - jest już na półce: " + b1.getAssignedBookshelf());
        } else if (super.size() < maxSize) {
            super.add(b1);
            b1.setAssigned(this);
        } else {
            throw new Exception("Nie mogę wstawić książki na półkę (" + this + ") - brak miejsca");
        }
    }

    public boolean remove(Book b) throws Exception {
        if (contains(b)) {
            b.setAssigned(null);
            return super.remove(b);
        } else {
            throw new Exception("Nie mogę zdjąć książki z półki (" + this + ") - nie jest na tej półce");
        }
    }

    public CopyOnWriteArrayList<Book> getBooks() {
        return this;
    }

    @Override
    public String toString() {
        return "Półka " + name;
    }
}
public class Book {
    private final String first;
    private final String second;
    private Bookshelf assignedBookshelf = null;

    public Book(String string, String string2) {
        first = string;
        second = string2;
    }

    @Override
    public String toString() {
        return first + " " + second;
    }

    public void setAssigned(Bookshelf bs) {
        assignedBookshelf = bs;
    }

    public Bookshelf getAssignedBookshelf() {
        return assignedBookshelf;
    }
}

To jest bardzo nieoptymalne rozwiązanie, ale najłatwiejsze do napisania :P

2

Zadanie jest ciekawe, będzie zatem alternatywne rozwiązanie.

public class Book 
{ 
    private String autor;
    private String tytul;
    public Bookshelf polka = null;
 
    public Book(String autor , String tytul)
    {
        this.autor = autor;
        this.tytul = tytul;
    }
 
    public String toString()
    {
        return (autor + " " + tytul);
    }
}
import java.util.*;
public class Bookshelf 
{ 
    private String nazwa;
    private int dlugosc;
    ArrayList<Book> books;
 
    Bookshelf(String nazwa, int dlugosc)
    {
        this.nazwa = nazwa;
        this.dlugosc = dlugosc;
        books = new ArrayList<Book>();
    }
 
    public void insert(Book ksiazka) throws Exception
    {
        if( ksiazka.polka != null )
        {
            throw new Exception("Nie mogę wstawić książki na półkę " + nazwa + " - jest już na półce: " + ksiazka.polka);
        }
        else
        {
            if(books.size()>=dlugosc)
            {
                throw new Exception("Nie mogę wstawić książki na półkę (Półka " + nazwa + " - brak miejsca");
            }
            books.add(ksiazka);
            ksiazka.polka=this;
        }
    }
 
    public ArrayList<Book> getBooks()
    {
        ArrayList<Book> kopia=new ArrayList<Book>(books);
        return kopia;
    }
 
    public void remove(Book ksiazka) throws Exception
    {
        boolean ok=books.remove(ksiazka);
        if(ok)
        {
            ksiazka.polka=null;
        }
        else
        {
            throw new Exception("Nie mogę zdjąć książki z półki " + nazwa + " - nie jest na tej półce");
        }
    }
 
    public String toString()
    {
        return "Polka "+ nazwa;
    } 
}
0

Dziękuje Panowie za pomoc: postanowiłem trochę zmienić swój kod , w następujący sposób i o dziwo dla mnie ta zmiana przyniosła pozytywny skutek co jeszcze bardziej mnie drażni. Bo nie rozumiem czemu. Modyfikuje przecież obiekt z pętli for tzn. książkę a jednak wszystko gra: Z wykładów wiem że pętla for dla kolekcji ma swoje ograniczenia polegające na tym że nie może modyfikować obiektów z tej pętli. A tu proszę modyfikuje książką i wszystko jest ok.
Niech ktoś proszę powie mi jaką zasadą mam się kierować bo rozumiem że teraz kod działa poprawnie ale nie wiem czemu działa więc to marna nauka.

Oczywiście zgłaszanie wyjątków do poprawy:


public class Bookshelf {

	private String nazwa;
	private int dlugosc;
	int liczbaKsiazek;
	Book[] polka;
	Book[] tmp;
	
	Bookshelf(String nazwa, int dlugosc){
		
		this.nazwa = nazwa;
		this.dlugosc = dlugosc;
		polka = new Book[dlugosc];
		
	}
	
	public void insert(Book ksiazka){
		
		//System.out.println("Wywolanie insert dla polki: " + nazwa);
		
		if( ksiazka.polka != null ){
			System.out.println("Nie mogę wstawić książki na półkę " + nazwa + " - jest już na półce: " + ksiazka.polka);
		}
		else{
			for(int i = 0 ; i < dlugosc ; i++){
				if( polka[i] == null ){
					polka[i] = ksiazka;
					ksiazka.polka = nazwa;
					ksiazka.pozycja = i ;
					liczbaKsiazek++;
					break;
				}
				if( (polka[i] != null) && (i == (dlugosc-1) ) ){
					System.out.println("Nie mogę wstawić książki na półkę (Półka " + nazwa + ") - brak miejsca");
				}
			}
		}
		
	}
	
    public Book[] getBooks(){
    	
    	tmp = new Book[liczbaKsiazek];
    	int itmp = 0;
    	
    	for(int i = 0 ; i < dlugosc ; i++){
    		if(polka[i] != null){
    			tmp[itmp] = polka[i];
    			itmp++;
    		}
    	}
    	
		return tmp;
    	
    }

	public void remove(Book ksiazka) {
		
		//System.out.println("Wywolanie remove dla polki: " + nazwa);
		
		if(ksiazka.polka == nazwa){
		
			    //System.out.println("Usunieto: "+ polka[ksiazka.pozycja] +" z: " + nazwa);
				polka[ksiazka.pozycja] = null;
				liczbaKsiazek--;
				ksiazka.polka = null;
				
			
		}
		else{
			System.out.println("Nie mogę zdjąć książki z półki " + nazwa + " - nie jest na tej półce");
		}
		
	}
	
	public String toString(){
		return ("Polka "+ nazwa);
		
	}
	

}
1

Kluczowy był ten fragment:

for(int i = 0 ; i < dlugosc ; i++){
     if( polka[i].equals(ksiazka) ){
          System.out.println("Usunieto: "+ polka[i] +" z: " + nazwa);
          polka[i].polka = null;

Książki były usuwane w kolejności dopisywania, do tablicy zwracanej przez getBooks() przepisałeś not null referencje, (tzn. z tablicy polka referencje z pozycji 0,1,2). Usunąłeś pierwszą książkę, w polka[0] pojawił się null, przy usuwaniu kolejnej książki powyższa pętla zaczynał się od:

   if(null.equals(ksiazka)){

...
null.polka=null;

Pierwotna wersja działałaby gdyby tablica tmp w funkcji getBooks() była tworzona od końca:

    public Book[] getBooks(){
            tmp = new Book[liczbaKsiazek];
            int itmp = 0;
            for(int i = dlugosc-1 ; i >= 0 ; i--){
                    if(polka[i] != null){
                            tmp[itmp] = polka[i];
                            itmp++;
                    }
            }
            return tmp;
    }
0

czyli null.equals(ksiazka) jest równe true?

1

Nieistotne, już to

if(null.equals(ksiazka)){

jest błędne.

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