Est-il possible d'utiliser l'API Java 8 Stream sur l'API Android <24?

89

J'ai lu cet article ici. Mais je ne peux toujours pas exécuter de code contenant les fonctionnalités de l'API Java 8 Stream telles que les suivantes sur minSdkVersion <24.

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

Cela ne fonctionne pas en raison du message d'erreur

L'appel nécessite le niveau d'API 24 (le minimum actuel est 15): java.util.Collection # stream

Alors, quelqu'un connaît-il une solution?

illimité101
la source
3
non, vous ne pouvez pas utiliser le flux java sous l'api 24. il existe des bibliothèques tierces qui implémentent la même chose bien que cela fonctionne
tyczj
1
J'ai une petite bibliothèque qui fait des choses similaires pour les apis inférieurs: github.com/smaspe/FunctionalIterables
njzk2
2
Voir stackoverflow.com/questions/39265004/… et stackoverflow.com/questions/39039566/… pour des questions (et réponses) similaires.
Sartorius
3
@PEMapModder Vous pouvez utiliser des expressions lambda et des références de méthode à l'aide du nouveau compilateur Jack ciblant Android aussi loin que Gingerbread. Ce que vous ne pouvez pas avoir sous le SDK 24, ce sont les méthodes d'interface par défaut / statique et les API spécifiques à Java 8 comme l'API Stream.
Sartorius
Vous pouvez utiliser la classe StreamSupport sous API 24
Özer Özcan

Réponses:

69

[réponse originale]

Vous ne pouvez pas utiliser les flux Java8 au niveau API <24.

Cependant, certaines bibliothèques rétroportent certaines des fonctionnalités de flux

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

https://github.com/konmik/solid

https://sourceforge.net/projects/streamsupport/ (mentionné par @sartorius dans un commentaire)

[mise à jour k3b 23/05/2019]

https://github.com/retrostreams/android-retrostreams est une retombée de streamsupport qui tire parti de la capacité d'Android Studio 3.x D8 / desugar toolchain à utiliser les méthodes d'interface par défaut et statiques à travers les limites des fichiers Jar. Il existe également des liens vers d'autres android-retroXXX ie pour CompletableFuture.

[mise à jour aeracode 2020-07-24]

Bonne nouvelle , nous pouvons désormais utiliser l'API Java 8 Stream et plus sans avoir besoin d'un niveau d'API minimum .

Robert Estivill
la source
9
Alors que solide et Lightweight-Stream-API sont certainement des options précieuses pour la programmation de type Stream, à mon humble avis, aucun d'entre eux ne peut même être considéré à distance comme un "backport" de l'API Java 8 Stream. Le seul projet que je connais qui puisse prétendre être proche en syntaxe et à égalité de fonctionnalités avec les flux Java 8 est streamsupport . Par exemple, il prend également en charge les flux parallèles. Bien que ce ne soit peut-être pas si important pour les développeurs Android.
Sartorius
IMO, Lightweight-Stream-API était le meilleur sur Android en raison du support Gradle et des extras ajoutés tels que "select", "groupBy", etc. github.com/aNNiMON/Lightweight-Stream-API#additional-operators .
LordParsley
2
@LordParsley streamsupport prend également en charge Gradle. Quant aux extras, c'est vrai. Si je comprends bien, étendre / détourner de l'API officielle Java 8 n'a jamais été un objectif de conception de streamsupport.
Sartorius
3
@Sartorius a raison - je recommande de consulter le miroir Github pour les détails d'utilisation et les références Gradle github.com/streamsupport/streamsupport
LordParsley
J'ai lu qu'en général les flux Java sont plus lents que les collections. stackoverflow.com/questions/22658322/... Qu'en est-il de ces backports?
Shikhar Shrivastav
12

Depuis la version 8.2 de DexGuard, il est possible d'utiliser l'API de flux Java 8 également sur les appareils Android <niveau de l'API 24. Pour ce faire, il faut inclure la bibliothèque streamsupport et DexGuard traduira tous les appels d'API de flux Java 8 vers le fichier fourni. bibliothèque. Aucune manipulation supplémentaire n'est nécessaire et les développeurs peuvent simplement coder à l'aide de l'API Java 8 streams fournie. Les dépendances sont également traduites automatiquement, il est donc possible d'utiliser des bibliothèques avec des fonctionnalités Java 8 également pour le développement Android.

Cette fonctionnalité sera également incluse dans ProGuard dans un proche avenir, restez à l'écoute.

Edit: Proguard 6.1.0 pour lequel il existe déjà une version bêta prend en charge le backporting Java 8 stream et time API.

T. Neidhart
la source
ce n'est pas la bibliothèque officielle
user25
Je n'ai aucune idée de la bibliothèque elle-même, mais je recommanderais de vérifier la licence de la bibliothèque avant de l'utiliser dans un projet commercial. Licence publique générale GNU, version 2, avec l'exception Classpath . Une couche doit probablement être confirmée.
Michal Harakal
5
@MichalHarakal il m'a fallu quelques secondes pour réaliser que la couche était en fait un avocat :)
superjos
6

Peut-être un peu tard à la fête, mais je viens de voir que si nous utilisons, java8.util.stream.StreamSupportnous pouvons exécuter la même approche de programmation fonctionnelle et l'utiliser avant Api 24. Par exemple, tiré de web3j -

StreamSupport.stream(transactionReceipt.getLogs())
            .map(log -> extractEventParameters(event, log))
            .filter(Objects::nonNull)
            .collect(Collectors.toList());
Abhriya Roy
la source
3
@AjahnCharles Dire aux gens d'utiliser simplement la langue B lorsque leur question porte sur la langue A n'est pas une bonne réponse. De nombreux projets sont encore écrits en Java.
mkuech
2
@AjahnCharles Vous faites un bon point pour attirer l'attention des lecteurs sur la possibilité d' envisager des changements dans l'écosystème Android. Cela dit, la question concerne une fonctionnalité spécifique de Java qui est toujours un langage officiellement pris en charge pour le développement Android. Changer, même si "seulement" l'hybridation de votre application, a un coût (courbe d'apprentissage, peut-être que son équipe ne la prend pas en charge, etc.) et cela nécessite de plonger dans bien plus que ce qui est demandé dans la question. Plus important encore, le commentaire ne traite pas de la façon dont Kotlin est une solution, ce qui la rend plus hors contexte et moins utile.
mkuech le
3
@AjahnCharles quand il est clairement mentionné Java 8 Stream API, je pense que la réponse devrait aussi être en JAVA!
Abhriya Roy le
1

Oui, ça l'est ! À partir d'AGP 4.0.0, nous pouvons utiliser l'API Stream et d'autres API Java 8+ (par exemple java.time)

Modifications minimales requises pour build.gradle de votre application :

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

dependencies {
  coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.9'
}
aéracode
la source
-1

Une autre solution que j'aime utiliser est d'utiliser statiquement les extensions de Kotlin sur des collections à partir de code Java, si le projet prend en charge les deux bien sûr :

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

Idem pour .map, .reduce, .first, etc ...

y.allam
la source
-6

Créez une interface.

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

Créez une méthode de filtrage.

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;
        }
    }

Utilisation du code

    public static class model {
            public String Name;
        }
List<model> models = new ArrayList<>();
            ...
            List<model> filtermodels = Filter(models,p-> p.Name.equals("filter"));
Yusuf Aydın
la source