Problem z wyrażeniem lambda

0

Cześć,
zwracam się do Was z jednym pytaniem, dlaczego to nie działa?
Posiadam Eclipse Neon i zainstalowane jdk 1.8
W liście book przechowują obiekty, które zawierają tytuł, autora itd.
Po wprowadzeniu książki chciałbym ją wyświetlić w taki sposób:
main

ArrayList<Book> book = new ArrayList<Book>();
OptionLibrary oLib = new OptionLibrary();
book = oLib.AddBook(book);
oLib.ShowBooks(book, b -> b.titleBook);//tutaj nie działa

metoda ShowBooks

public void ShowBooks(ArrayList<Book> book, CheckBook verification)
	{
		for(Book fBook : book)
		{
			if(verification.canRemove(fBook))
				System.out.println(fBook);
		}
	}

CheckBook

public interface CheckBook
{
	String titleBook (Book book);
	String author (Book book);
	int isbn (Book book);
	int sizeBook (Book book);
	boolean canRemove (Book book);
}

PS. uczę się lambdy, a jak się nauczę to później strumienie - to tak w razie "wu"

0

Nie nie działa, ale się nie kompiluje !?!?!?!?
Może wkleisz z łaski swojej błąd?

EDIT: Mówisz kompilatorowi tak:
Wywołaj ShowBooks z listą książek i interfejsem CheckBook, który ma 5 metod ale ja Ci tutaj daję jedną (nie wiem którą - zgadnij), i ta metoda biorąc Book zwróci String tytuł.

0

No to w sumie nie kompiluje się i nie działa:

Exception in thread "main" java.lang.Error: Unresolved compilation problems: 
	The method ShowBooks(ArrayList<Book>, CheckBook) in the type OptionLibrary is not applicable for the arguments (ArrayList<Book>, (<no type> b) -> {})
	The target type of this expression must be a functional interface

	at Library.main(Library.java:10)
0

Lambda - to szybki sosób na zapis metody / zachowania bez deklarowania klasy implementującej interfejs np.

Jeżeli masz Interfejs z jedną metodą i ma on adnotację @FunctionalInterface to wtedy nie musisz tworzyć klasy która go implementuje, a możesz szybko przekazać lambdę

WNIOSEK: Twój interfejs CheckBook nie ma adnotacji @FunctionalInterface i ma 5 metod więc nie możesz zastąpić go lambdą.
PORADA: Twoja funkcja ShowBooks nie powinna przyjmować tego interfejsu a np. interfejs Predicate<Book>

0

Nie da się zrobić lambdy z interfejsu który ma więcej niż 1 metodę (która nie jest default) bo nie byłoby wiadomo którą z tych metod lambda "implementuje".

0

No dobra więc tak, zmieniłem CheckBook na:

public interface Predicate

metodę ShowBook zmieniłem tak:

public void ShowBooks(ArrayList<Book> book, Predicate<Book> verification)

a tej lambdy niestety nie potrafię zmienić...

0
public void ShowBooks(books, b -> b.startsWith("A"))

Czyli przekazuję funkcji Predykat (który musi zmieniać Book na boolean), w moim przypadku wyświetlone zostaną książki o tytule zaczynającym się wielką literą A

0

No właśnie nie bardzo to działa, tzn w ogóle nie działa - nie kompiluje się.

public void ShowBooks(ArrayList<Book> book, Predicate<Book> verification)

Typ Predicate nie jest generyczny

oLib.ShowBooks(book, b -> b.titleBook);

The method ShowBooks(ArrayList<Book>, (<no type="type"> b) -> {}) is undefined for the type OptionLibrary

0

Predykat to metoda, która Book zamienia do boolean. A Ty cały czas zmieniasz Book na String.

0

Ciężki temat, czyli w Predicate musi być tylko jedna metoda typu boolean więc najlepiej jakby to była metoda generyczna jeśli chcę wypisać wszystkie wartości książki, tak?

0

Nie do końca chyba rozumiesz, polecam więcej poczytać.

  1. Chcesz napisać metodę wyświetlającą listę książek.
  2. Chcesz aby ta metoda była bardziej ogólna tj. dawała możliwość np. zawężania wyników.

W starej Javie musiałbyś napisać to tak:

    public interface DecisionMaker{
        boolean decideWhetherToShow(Book book);
    }
    
    public void showBooks(List<Book> books, DecisionMaker decisionMaker){
        for (Book book : books){
            if(decisionMaker.decideWhetherToShow(book)){
                System.out.print(book);
            }
        }
    }

   public void test(){
        DecisionMaker titleNotEmptyDecisionMaker = new DecisionMaker() {
            @Override
            public boolean decideWhetherToShow(Book book) {
                return book.getTitle() != null;
            }
        };
        List<Book> books = new ArrayList<>();
        
        showBooks(books, titleNotEmptyDecisionMaker)
    }

W Javie 1.8 nie trzeba już tworzyć tej anonimowej klasy:

public void test(){
        List<Book> books = new ArrayList<>();

        showBooks(books, b -> b.getTitle() != null);
    }
    }

Dodatkowo nie musisz nawet mieć interfejsu DecisionMaker a wykorzystać Predicate<Book>

EDIT: Jeżeli chcesz przekonwertować listę książek na listę tytułów to nie używasz Predicate (bo on konwertuje Book na warunek logiczny boolean), a innego interfejsu np. Function<Book, String> który jak sama nazwa mówi jest funkcją która przyjmuje Book, a zwraca String.

0

Ok już mniej więcej rozumiem, w takim wypadku jeśli mógłbyś powiedzieć jak to wykorzystać bez interfejsu byłbym wdzięczny.

PS. Tutaj jest błąd, a raczej nie błąd bo wszystko się kompiluje ale daje wynik [Book@41629346]

public void showBooks(List<Book> books, DecisionMaker decisionMaker){
        for (Book book : books){
            if(decisionMaker.decideWhetherToShow(book)){
                System.out.print(book); //to nie wyświetla poprawnie
                System.out.print(book.titleBook); //to już tak, jest jakiś patent aby nie wypisywać book.title, book.author, book.costam?
            }
        }
    }
0

Zaimplementuj toString().

0

Mógłby mi ktoś powiedzieć jak wykorzystać lambdę bez wykorzystania interfejsu?

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