Можно ли использовать Java 8 Stream API в Android API <24?

89

Я прочитал этот пост здесь. Но все же я не могу запустить код, содержащий функции Java 8 Stream API, подобные приведенному ниже, на minSdkVersion <24.

List<Car> newCars = cars.stream()
                        .filter(s -> s.getColor().equals("red"))
                        .collect(Collectors.toList());

Это не запускается из-за сообщения об ошибке

Для вызова требуется уровень API 24 (текущий мин. 15): java.util.Collection # stream

Так кто-нибудь знает решение?

неограниченно101
источник
3
нет, вы не можете использовать поток java ниже api 24. Существуют сторонние библиотеки, которые реализуют то же самое, хотя и работают
tyczj
1
У меня есть небольшая библиотека, которая делает аналогичные вещи для более низких API: github.com/smaspe/FunctionalIterables
njzk2
2
См. Stackoverflow.com/questions/39265004/… и stackoverflow.com/questions/39039566/… для аналогичных вопросов (и ответов).
Сарториус
3
@PEMapModder. Вы можете использовать лямбда-выражения и ссылки на методы, используя новый компилятор Jack, ориентированный на Android еще в Gingerbread. То, что вы не можете иметь ниже SDK 24, - это методы статического интерфейса по умолчанию и специальные API Java 8, такие как Stream API.
Сарториус
Вы можете использовать класс StreamSupport под API 24
Özer Özcan

Ответы:

69

[оригинальный ответ]

Вы не можете использовать потоки Java8 на уровне API <24.

Однако есть библиотеки, которые поддерживают некоторые функции потока.

https://github.com/aNNiMON/Lightweight-Stream-API

https://github.com/konmik/solid

https://sourceforge.net/projects/streamsupport/ (упоминается @sartorius в комментарии)

[обновление k3b 2019-05-23]

https://github.com/retrostreams/android-retrostreams - это дополнительный продукт от streamsupport, который использует возможности Android Studio 3.x D8 / desugar, позволяющие использовать стандартные и статические методы интерфейса через границы файлов Jar. Также есть ссылки на другие android-retroXXX, т.е. на CompletableFuture.

[обновить код aeracode 2020-07-24]

Хорошие новости , теперь мы можем использовать Java 8 Stream API и многое другое, не требуя минимального уровня API .

Роберт Эстивилл
источник
9
Хотя Solid и Lightweight-Stream-API , безусловно, являются ценными вариантами для потокового программирования, IMHO ни один из них не может даже удаленно рассматриваться как «бэкпорт» Java 8 Stream API. Единственный известный мне проект, который может претендовать на близость по синтаксису и функциональность к потокам Java 8, - это streamsupport . Например, он также поддерживает параллельные потоки. Хотя для разработчиков Android это может быть не так важно.
Сарториус
IMO, Lightweight-Stream-API был лучшим на Android из-за поддержки Gradle и добавленных дополнительных функций, таких как «select», «groupBy» и т . Д. Github.com/aNNiMON/Lightweight-Stream-API#additional-operators .
LordParsley
2
@LordParsley streamsupport также поддерживает Gradle. Что касается дополнительных услуг, да, это правда. Насколько я понимаю, расширение / отклонение от официального API Java 8 никогда не было целью разработки поддержки потоковой передачи.
Sartorius
3
@Sartorius прав - я рекомендую проверить зеркало Github для получения подробной информации об использовании и Gradle refs github.com/streamsupport/streamsupport
LordParsley
Я читал, что в целом потоки Java работают медленнее, чем коллекции. stackoverflow.com/questions/22658322/… А как насчет этих резервных копий?
Шихар Шривастав
12

Начиная с выпуска DexGuard 8.2, можно использовать API потоков Java 8 также на устройствах Android <уровень API 24. Для этого необходимо включить библиотеку поддержки потоков, и DexGuard переведет все вызовы API потоков Java 8 в предоставленные библиотека. Никакой дополнительной обработки не требуется, и разработчики могут просто кодировать, используя предоставленный API потоков Java 8. Зависимости также переводятся автоматически, поэтому библиотеки с функциями Java 8 можно использовать также для разработки под Android.

Эта функция также будет включена в ProGuard в ближайшем будущем, следите за обновлениями.

Изменить: Proguard 6.1.0, для которого уже существует бета-версия, поддерживает обратный перенос потока Java 8 и API времени.

Т. Нейдхарт
источник
это не официальная библиотека
user25
Я понятия не имею о самой библиотеке, но я бы рекомендовал проверить лицензию библиотеки перед использованием в коммерческом проекте. Стандартная общественная лицензия GNU, версия 2, с исключением пути к классам . Наверное, слой должен подтвердить.
Михал Харакал
5
@MichalHarakal, мне потребовалась пара секунд, чтобы понять, что этот слой на самом деле был юристом :)
superjos
6

Возможно, мы немного опоздаем на вечеринку, но я только что увидел, что если мы используем, java8.util.stream.StreamSupportто мы можем запустить тот же подход функционального программирования и использовать его до Api 24. Например, взято из web3j -

StreamSupport.stream(transactionReceipt.getLogs())
            .map(log -> extractEventParameters(event, log))
            .filter(Objects::nonNull)
            .collect(Collectors.toList());
Абхрия Рой
источник
3
@AjahnCharles Сказать людям просто использовать язык B, когда их вопрос касается языка A, - не лучший ответ. Многие проекты до сих пор написаны на Java.
mkuech
2
@AjahnCharles. Вы хорошо замечаете, что привлекаете внимание читателей к возможному рассмотрению изменений в экосистеме Android. Тем не менее, вопрос касается специфической особенности Java, которая по-прежнему официально поддерживается для разработки под Android. Переключение, даже если «только» гибридизацию приложение, приносит стоимость (кривая обучения, может быть , их команда не поддерживает его, и т.д.) , а это требует погружения в пути больше , чем спрашивается в вопросе. Что еще более важно, в комментарии не говорится о том, как Kotlin является решением, что делает его более неконтекстным и менее полезным.
mkuech
3
@AjahnCharles, когда это четко упомянуто Java 8 Stream API, я думаю, ответ также должен быть на JAVA!
Абхрия Рой,
1

Да, это так ! Начиная с AGP 4.0.0 мы можем использовать Stream API и некоторые другие API Java 8+ (например java.time)

Минимальные необходимые изменения в build.gradle вашего приложения :

android {
  compileOptions {
    // Flag to enable support for the new language APIs
    coreLibraryDesugaringEnabled true
  }
}

dependencies {
  coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.9'
}
аэракод
источник
-1

Другое решение, которое мне нравится использовать, - это статическое использование расширений Kotlin поверх коллекций из кода Java, если проект, конечно, поддерживает оба :

List<Car> newCars = CollectionsKt.filter(cars, s -> s.getColor().equals("red"));

То же самое для .map, .reduce, .first, ... и т.д.

y.allam
источник
-6

Создайте интерфейс.

public interface Pre<T,R> {
            R get(T item);
        }

Создайте метод фильтрации.

public static  <T> List<T> Filter(List<T> list, Pre<T,Boolean> pre) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
        {
            return list.stream().filter(p -> pre.get(p)).collect(Collectors.toList());
        }
        else
        {
            List<T> col = new ArrayList<T>();
            for (int i = 0 ; i < list.size() ; i++)
                if (pre.get(list.get(i)))
                    col.add(list.get(i));
            return col;
        }
    }

Использование кода

    public static class model {
            public String Name;
        }
List<model> models = new ArrayList<>();
            ...
            List<model> filtermodels = Filter(models,p-> p.Name.equals("filter"));
Юсуф Айдын
источник