É possível usar a API Java 8 Stream na API Android <24?

89

Eu li esse post aqui. Mas ainda não consigo executar o código que contém os recursos da API Java 8 Stream como o seguinte em minSdkVersion <24.

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

Isso não funciona devido à mensagem de erro

A chamada requer API de nível 24 (o mínimo atual é 15): java.util.Collection # stream

Então, alguém conhece uma solução?

ilimitado 101
fonte
3
não, você não pode usar o fluxo de java abaixo da API 24. existem bibliotecas de terceiros que implementam a mesma coisa embora funcionem
tyczj
1
Eu tenho uma pequena biblioteca que faz coisas semelhantes para apis inferiores: github.com/smaspe/FunctionalIterables
njzk2
2
Consulte stackoverflow.com/questions/39265004/… e stackoverflow.com/questions/39039566/… para perguntas (e respostas) semelhantes.
Sartorius de
3
@PEMapModder Você pode usar expressões lambda e referências de método usando o novo compilador Jack voltado para o Android desde Gingerbread. O que você não pode ter abaixo do SDK 24 são métodos de interface padrão / estática e APIs específicas do Java 8, como a API Stream.
Sartorius
Você pode usar a classe StreamSupport na API 24
Özer Özcan

Respostas:

69

[resposta original]

Você não pode usar fluxos Java8 no nível de API <24.

No entanto, existem algumas bibliotecas que suportam algumas das funcionalidades de fluxo

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

https://github.com/konmik/solid

https://sourceforge.net/projects/streamsupport/ (mencionado por @sartorius no comentário)

[atualizar k3b 23/05/2019]

https://github.com/retrostreams/android-retrostreams é uma derivação do streamsupport que aproveita a capacidade do conjunto de ferramentas D8 / desugar do Android Studio 3.x de usar métodos estáticos e padrão de interface através dos limites do arquivo Jar. Também há links para outro android-retroXXX, ou seja, para CompletableFuture.

[atualizar aeracode 2020-07-24]

Boas notícias , agora podemos usar a API Java 8 Stream e muito mais sem exigir um nível mínimo de API .

Robert Estivill
fonte
9
Embora solid e Lightweight-Stream-API sejam certamente opções valiosas para programação semelhante a Stream, IMHO nenhum deles pode ser considerado, mesmo remotamente, um "backport" do Java 8 Stream API. O único projeto que conheço que pode reivindicar ser próximo em sintaxe e no mesmo nível de funcionalidade para fluxos de Java 8 é streamsupport . Por exemplo, ele também oferece suporte a fluxos paralelos. Embora isso possa não ser tão importante para desenvolvedores Android.
Sartorius
IMO, Lightweight-Stream-API era o melhor no Android por causa do suporte Gradle e extras adicionados como "select", "groupBy", etc. github.com/aNNiMON/Lightweight-Stream-API#additional-operators .
LordParsley
2
@LordParsley streamsupport também tem suporte para Gradle. Quanto aos extras, sim, é verdade. Pelo que entendi, estender / desviar da API Java 8 oficial nunca foi um objetivo de design do streamsupport.
Sartorius
3
@Sartorius está certo - eu recomendo verificar o espelho do Github para obter detalhes de uso e as referências do Gradle github.com/streamsupport/streamsupport
LordParsley
Eu li que em geral Java Streams são mais lentos do que coleções. stackoverflow.com/questions/22658322/… E quanto a esses backports?
Shikhar Shrivastav
12

Desde o lançamento 8.2 do DexGuard é possível usar a API Java 8 streams também em dispositivos Android <nível API 24. A fim de fazê-lo, é preciso incluir o streamsupport biblioteca e DexGuard irá traduzir todos os 8 fluxo de chamadas de API Java para o fornecido biblioteca. Nenhuma manipulação adicional é necessária e os desenvolvedores podem simplesmente codificar usando a API de fluxos Java 8 fornecida. As dependências também são traduzidas automaticamente, portanto, é possível usar bibliotecas com recursos do Java 8 também para desenvolvimento em Android.

Esse recurso também será incluído no ProGuard em um futuro próximo, fique atento.

Editar: Proguard 6.1.0 para o qual já existe uma versão beta suporta backporting Java 8 stream e time API.

T. Neidhart
fonte
não é uma biblioteca oficial
usuário
Não tenho nenhuma ideia da biblioteca em si, mas recomendo que verifique a licença da biblioteca antes de usar em um projeto comercial. GNU General Public License, versão 2, com a exceção Classpath . Provavelmente, uma camada precisa confirmar.
Michal Harakal
5
@MichalHarakal demorei alguns segundos para perceber que a camada era na verdade advogado :)
superjos
6

Pode ser um pouco tarde para a festa, mas acabei de ver que se usarmos java8.util.stream.StreamSupport, podemos executar a mesma abordagem de programação funcional e usá-la antes do Api 24. Ex. Retirado do web3j -

StreamSupport.stream(transactionReceipt.getLogs())
            .map(log -> extractEventParameters(event, log))
            .filter(Objects::nonNull)
            .collect(Collectors.toList());
Abhriya Roy
fonte
3
@AjahnCharles Dizer às pessoas para usarem apenas a linguagem B quando sua pergunta for sobre a linguagem A não é uma boa resposta. Muitos projetos ainda são escritos em Java.
mkuech
2
@AjahnCharles Você fez um bom argumento sobre chamar a atenção dos leitores para a possibilidade de considerar mudanças no ecossistema Android. Dito isso, a questão é sobre um recurso específico do Java que ainda é uma linguagem oficialmente suportada para desenvolvimento Android. Mudar, mesmo que "apenas" hibridizar seu aplicativo, acarreta um custo (curva de aprendizado, talvez sua equipe não suporte isso, etc) e isso requer um mergulho muito mais do que o que está sendo perguntado na pergunta. Mais importante ainda, o comentário não aborda como o Kotlin é uma solução, o que o torna mais fora do contexto e menos útil.
mkuech
3
@AjahnCharles quando for claramente mencionado Java 8 Stream API, eu acho, a resposta também deveria estar em JAVA!
Abhriya Roy,
1

Sim, é verdade ! A partir do AGP 4.0.0, podemos usar a API Stream e algumas outras APIs Java 8+ (por exemplo java.time)

Mudanças mínimas necessárias no build.gradle do seu aplicativo :

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

dependencies {
  coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.9'
}
aeracode
fonte
-1

Outra solução que gosto de usar é usar estaticamente as extensões de Kotlin em vez de coleções do código Java, se o projeto suportar ambos, é claro :

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

Mesmo para .map, .reduce, .first, etc ...

y.allam
fonte
-6

Crie uma interface.

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

Crie um método de filtro.

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

Usando código

    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
fonte