Вопрос про работу метода foreach() интерфейса Iterable

157
25 сентября 2021, 18:00

Есть такой код

 List<String> strings = Arrays.asList("eeny", "meeny", "miny", "mo");
        strings.forEach(string -> System.out.println(string));

Непонятно как он работает, за исключением того, что знаю что лямбда работает по той причине, что интерфейс Consumer является функциональным интерфейсом.

Но вот остальное как то очень запутанно. Возможно вся проблема в том, что у меня сложности в понимании следующего выражения находящиеся в интерфейсе Iterable

default void forEach(Consumer<? super T> action) {/*содержание тела метода 
                                                  мне понятна, поэтому не 
                                                  скопировал тут*/}

Просьба: Будет очень полезно, если пошагово напишите алгоритм работы данного кода.

Внимание: Если данный вопрос вдруг оказался дубликатом, тогда просто вставьте ссылку в комментах, без негативных голосов. Если содержание ссылки дает исчерпывающий ответ, тогда я свой вопрос удалю.

Answer 1

Поясняю, метод forEach() в качестве аргумента принимает функциональный интерфейс, а именно интерфейс Consumer<T>. Функциональный интерфейс - это интерфейс, который имеет только один метод. Для чего они нужны? В основном для лямбда-выражений. Итак, структура данного функционального интерфейса представлена следующим образом:

То есть, данный интерфейс принимает какой-то агрумента типа T и ничего не возвращает (void). Так же у него есть только один метод - accept(). Для "активации" нашего действия необходимо вызвать метод accept(), который нам бы пришлось реализовывать, например, с помощью анонимного класса, например вот так:

Consumer<T> cons = new Consumer<>() {
     public void accept(T arg){
         System.out.println(arg);
     }
 }

Согласитесь, не очень удобно каждый раз создавать анонимный класс. Но к нашему счастью лямбда-выражения освобождают нас от этой рутины. Чтобы выполнить этот метод нам достаточно просто написать: s -> System.out.println(s). Где s - это аргумент, который мы передаем в наш фантомный метод accept(), а System.out.println(s) - это то действие, которые мы выполняем в этом методе accept(). Кстати, гораздо проще передать ссылку на метод: forEach(System.out::println). В этом случае каждая перебранная переменная автоматические становится аргументом, который мы передаем в метод accept() и для каждой мы выполняем метод System.out.println().

Answer 2

Use the Source, Luke

Первоисточник достаточно ясно показывает дефолтную имплементацию, а именно:

public interface Iterable<T> {
  default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
  }
}

Грубо говоря, в кишках сидит конструкция for-each, которая работает через:

for (Iterator<T> t = iterable.iterator(); t.hasNext();) {
    T item = t.next();
    //blah-blah
}
READ ALSO
LocalDate или Date

LocalDate или Date

Сколько бы примеров и полей с датами на Java я не видел, всегда (или почти всегда) используют класс DateПри этом, я думаю, всем известно, что класс...

91
WebView как браузер по умолчанию или как открывать ссылки в своём браузере

WebView как браузер по умолчанию или как открывать ссылки в своём браузере

У меня есть простой браузерМне надо чтобы в нём открывались ссылки, как например в Google Chrome

343
IllegalArgumentExeption BroadcastReceiver

IllegalArgumentExeption BroadcastReceiver

Я получаю уведомления в панели разработчика что в приложении происходят сбои, а именно IllegalArgumentExeption на 9 Андроиде по большей части на устройствах...

150
не запускается telegram бот на spring boot

не запускается telegram бот на spring boot

Вот гит - https://githubcom/DeadSidert/commybot

117