JavaRush /Blog Jawa /Random-JV /Lambdas lan referensi metode ing ArrayList.forEach - cara...

Lambdas lan referensi metode ing ArrayList.forEach - cara kerjane

Diterbitake ing grup
Pambuka ekspresi lambda ing pencarian Java Syntax Zero diwiwiti kanthi conto sing spesifik:
ArrayList<string> list = new ArrayList<>();
Collections.addAll(list, "Hello", "How", "дела?");

list.forEach( (s) -> System.out.println(s) );
Penulis saka kuliah parse lambdas lan referensi metode nggunakake standar kanggo saben fungsi kelas ArrayList. Secara pribadi, aku angel ngerti makna apa sing kedadeyan, amarga implementasine fungsi iki, uga antarmuka sing ana gandhengane, tetep "ing hood". Endi argumen (s) asale , ing ngendi fungsi println () dilewati minangka pitakonan sing kudu dijawab dhewe. Untunge, kanthi IntelliJ IDEA, kita bisa kanthi gampang ndeleng internal kelas ArrayList lan ngilangi mie iki wiwit wiwitan. Yen sampeyan uga ora ngerti apa-apa lan pengin tokoh metu, Aku bakal nyoba kanggo mbantu karo iki paling sethithik. Ekspresi Lambda lan ArrayList.forEach - cara kerjane Saka kuliah kita wis ngerti yen ekspresi lambda minangka implementasi antarmuka fungsional . Sing, kita wara-wara antarmuka karo siji fungsi, lan nggunakake lambda kanggo njlèntrèhaké apa fungsi iki. Kanggo nindakake iki, sampeyan kudu: 1. Nggawe antarmuka fungsional; 2. Nggawe variabel sing jinise cocog karo antarmuka fungsional; 3. Nemtokake variabel iki minangka ekspresi lambda sing nggambarake implementasine fungsi kasebut; 4. Nelpon fungsi kanthi ngakses variabel (mbok menawa aku dadi kasar ing terminologi, nanging iki minangka cara sing paling jelas). Aku bakal menehi conto prasaja saka Google, nyedhiyakake komentar sing rinci (matur nuwun kanggo penulis situs metanit.com):
interface Operationable {
    int calculate(int x, int y);
    // Единственная функция в интерфейсе — значит, это функциональный интерфейс,
    // который можно реализовать с помощью лямбды
}

public class LambdaApp {

    public static void main(String[] args) {

        // Создаём переменную operation типа Operationable (так называется наш функциональный интерфейс)
        Operationable operation;
        // Прописываем реализацию функции calculate с помощью лямбды, на вход подаём x и y, на выходе возвращаем их сумму
        operation = (x,y)->x+y;

        // Теперь мы можем обратиться к функции calculate через переменную operation
        int result = operation.calculate(10, 20);
        System.out.println(result); //30
    }
}
Saiki ayo bali menyang conto saka ceramah. Sawetara unsur jinis String ditambahake menyang koleksi dhaptar . Unsur kasebut banjur dijupuk nggunakake fungsi standar forEach , sing diarani ing obyek dhaptar . Ekspresi lambda karo sawetara parameter aneh diterusake minangka argumen kanggo fungsi kasebut .
ArrayList<string> list = new ArrayList<>();
Collections.addAll(list, "Hello", "How", "дела?");

list.forEach( (s) -> System.out.println(s) );
Yen sampeyan ora langsung ngerti apa sing kedadeyan ing kene, mula sampeyan ora piyambak. Untunge, IntelliJ IDEA duwe trabasan keyboard sing apik: Ctrl+Left_Mouse_Button . Yen kisaran forEach lan klik kombinasi iki, kode sumber kelas ArrayList standar bakal mbukak, ing ngendi kita bakal weruh implementasine metode forEach :
public void forEach(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    final int expectedModCount = modCount;
    final Object[] es = elementData;
    final int size = this.size;
    for (int i = 0; modCount == expectedModCount && i < size; i++)
        action.accept(elementAt(es, i));
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}
Kita weruh manawa argumen input minangka tumindak saka jinis Konsumen . Ayo pindhah kursor ing tembung Konsumen banjur pencet kombinasi ajaib Ctrl+LMB maneh . Katrangan babagan antarmuka Konsumen bakal mbukak . Yen kita mbusak implementasine standar saka iku (ora penting kanggo kita saiki), kita bakal weruh kode ing ngisor iki:
public interface Consumer<t> {
   void accept(T t);
}
Dadi. Kita duwe antarmuka Konsumen kanthi fungsi nampa siji sing nampa siji argumen saka jinis apa wae. Amarga mung ana siji fungsi, mula antarmuka fungsional, lan implementasine bisa ditulis liwat ekspresi lambda. Kita wis weruh yen ArrayList nduweni fungsi forEach sing njupuk implementasi antarmuka Konsumen minangka argumen aksi . Kajaba iku, ing fungsi forEach kita nemokake kode ing ngisor iki:
for (int i = 0; modCount == expectedModCount && i < size; i++)
    action.accept(elementAt(es, i));
The for loop ateges iterates liwat kabeh unsur ArrayList. Nang daur ulang kita ndeleng telpon menyang fungsi nampa obyek tumindak - elinga carane kita disebut operation.calculate? Unsur koleksi saiki diterusake menyang fungsi nampa . Saiki kita bisa bali menyang ekspresi lambda asli lan ngerti apa sing ditindakake. Ayo ngumpulake kabeh kode ing siji tumpukan:
public interface Consumer<t> {
   void accept(T t); // Функция, которую мы реализуем лямбда-выражением
}

public void forEach(Consumer<? super E> action) // В action хранится an object Consumer, в котором функция accept реализована нашей лямбдой {
    Objects.requireNonNull(action);
    final int expectedModCount = modCount;
    final Object[] es = elementData;
    final int size = this.size;
    for (int i = 0; modCount == expectedModCount && i < size; i++)
        action.accept(elementAt(es, i)); // Вызываем нашу реализацию функции accept интерфейса Consumer для каждого element коллекции
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

//...

list.forEach( (s) -> System.out.println(s) );
Ekspresi lambda kita minangka implementasi saka fungsi nampa sing diterangake ing antarmuka Konsumen . Nggunakake lambda, kita nemtokake manawa fungsi nampa njupuk argumen s lan ditampilake ing layar. Ekspresi lambda diterusake menyang fungsi forEach minangka argumen aksi , sing nyimpen implementasi antarmuka Konsumen . Saiki fungsi forEach bisa nelpon implementasine antarmuka Konsumen kanthi baris kaya iki:
action.accept(elementAt(es, i));
Dadi, argumen input s ing ekspresi lambda minangka unsur liyane saka koleksi ArrayList , sing diterusake menyang implementasine antarmuka Konsumen . Iku kabeh: kita wis nganalisa logika ekspresi lambda ing ArrayList.forEach. Referensi kanggo metode ing ArrayList.forEach - kepiye cara kerjane? Tahap sabanjure ing ceramah yaiku ndeleng referensi metode. Bener, dheweke ngerti kanthi cara sing aneh - sawise maca ceramah, aku ora duwe kesempatan kanggo ngerti apa kode iki:
list.forEach( System.out::println );
Pisanan, teori sethitik maneh. Referensi metode , kanthi kasar banget, minangka implementasi antarmuka fungsional sing diterangake dening fungsi liyane . Maneh, aku bakal miwiti karo conto prasaja:
public interface Operationable {
    int calculate(int x, int y);
    // Единственная функция в интерфейсе — значит, это функциональный интерфейс
}

public static class Calculator {
    // Создадим статический класс Calculator и пропишем в нём метод methodReference.
    // Именно он будет реализовывать функцию calculate из интерфейса Operationable.
    public static int methodReference(int x, int y) {
        return x+y;
    }
}

public static void main(String[] args) {
    // Создаём переменную operation типа Operationable (так называется наш функциональный интерфейс)
    Operationable operation;
    // Теперь реализацией интерфейса будет не лямбда-выражение, а метод methodReference из нашего класса Calculator
    operation = Calculator::methodReference;

    // Теперь мы можем обратиться к функции интерфейса через переменную operation
    int result = operation.calculate(10, 20);
    System.out.println(result); //30
}
Ayo bali menyang conto saka ceramah:
list.forEach( System.out::println );
Ayo kula ngelingake yen System.out minangka obyek saka jinis PrintStream sing nduweni fungsi println . Ayo kisaran println banjur klik Ctrl+LMB :
public void println(String x) {
    if (getClass() == PrintStream.class) {
        writeln(String.valueOf(x));
    } else {
        synchronized (this) {
            print(x);
            newLine();
        }
    }
}
Wigati loro fitur utama: 1. Fungsi println ora ngasilake apa-apa (void). 2. Fungsi println nampa siji argumen minangka input. Apa ora ngelingake sampeyan apa-apa?
public interface Consumer<t> {
   void accept(T t);
}
Bener - tandha fungsi accept minangka kasus sing luwih umum saka tandha cara println ! Iki tegese sing terakhir bisa digunakake kanthi sukses minangka referensi kanggo metode - yaiku, println dadi implementasi spesifik saka fungsi accept :
list.forEach( System.out::println );
Kita ngliwati fungsi println obyek System.out minangka argumen kanggo fungsi forEach . Prinsipe padha karo lambda: saiki forEach bisa ngirim unsur koleksi menyang fungsi println liwat action.accept(elementAt(es, i)) call . Nyatane, iki saiki bisa diwaca minangka System.out.println(elementAt(es, i)) .
public void forEach(Consumer<? super E> action) // В action хранится an object Consumer, в котором функция accept реализована методом println {
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        final Object[] es = elementData;
        final int size = this.size;
        for (int i = 0; modCount == expectedModCount && i < size; i++)
            action.accept(elementAt(es, i)); // Функция accept теперь реализована методом System.out.println!
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
Mugi sing aku wis clarified kahanan ing paling sethitik kanggo wong-wong sing anyar kanggo lambdas lan referensi cara. Ing kesimpulan, aku nyaranake buku misuwur "Jawa: A Beginner Guide" dening Robert Schildt - ing mratelakake panemume, lambdas lan referensi fungsi diterangake cukup sensibly ing.
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION