Czy można używać Java 8 Stream API na Android API <24?

89

Przeczytałem ten post tutaj. Ale nadal nie mogę uruchomić kodu zawierającego funkcje Java 8 Stream API, takie jak poniższe na minSdkVersion <24.

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

To nie działa z powodu komunikatu o błędzie

Wywołanie wymaga interfejsu API na poziomie 24 (obecnie minimum to 15): java.util.Collection # stream

Czy ktoś zna rozwiązanie?

nieograniczony101
źródło
3
nie, nie możesz używać strumienia java poniżej api 24. istnieją biblioteki innych firm, które implementują to samo, chociaż działają
tyczj
1
Mam małą bibliotekę, która robi podobne rzeczy dla niższych apis: github.com/smaspe/FunctionalIterables
njzk2
2
Zobacz stackoverflow.com/questions/39265004/ ... i stackoverflow.com/questions/39039566/ ... aby uzyskać podobne pytania (i odpowiedzi).
Sartorius
3
@PEMapModder Ty może używać wyrażeń lambda i referencje Metoda z zastosowaniem nowego kompilatora Jack kierowania Android już w Piernika. To, czego nie możesz mieć poniżej SDK 24, to domyślne / statyczne metody interfejsu i specyficzne dla Java 8 interfejsy API, takie jak Stream API.
Sartorius
Możesz skorzystać z klasy StreamSupport w API 24
Özer Özcan

Odpowiedzi:

69

[oryginalna odpowiedź]

Nie można używać strumieni Java8 na poziomie API <24.

Istnieją jednak biblioteki, które obsługują niektóre funkcje strumienia

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

https://github.com/konmik/solid

https://sourceforge.net/projects/streamsupport/ (wspomniane przez @sartorius w komentarzu)

[aktualizacja k3b 2019-05-23]

https://github.com/retrostreams/android-retrostreams to spinoff ze streamsupport, który wykorzystuje możliwości Android Studio 3.x D8 / desugar toolchain do używania domyślnych i statycznych metod interfejsu w granicach plików Jar. Istnieją również linki do innych android-retroXXX, tj. Dla CompletableFuture.

[aktualizacja aeracode 2020-07-24]

Dobra wiadomość , teraz możemy używać Java 8 Stream API i więcej bez wymagania minimalnego poziomu API .

Robert Estivill
źródło
9
Podczas gdy solidne i Lightweight-Stream-API są z pewnością wartościowymi opcjami dla programowania podobnego do Streamu, IMHO żadnego z nich nie można nawet zdalnie uznać za „zaplecze” Java 8 Stream API. Jedynym projektem, o którym wiem, który może twierdzić, że jest zbliżony składnią i funkcjonalnie równy strumieniom Java 8, jest obsługa strumieni . Na przykład obsługuje również strumienie równoległe. Chociaż może to nie być takie ważne dla programistów Androida.
Sartorius
IMO, Lightweight-Stream-API było najładniejsze na Androidzie ze względu na obsługę Gradle i dodane dodatki, takie jak „select”, „groupBy” itp . Github.com/aNNiMON/Lightweight-Stream-API#additional-operators .
LordParsley
2
@LordParsley streamsupport obsługuje również Gradle. Jeśli chodzi o dodatki, to prawda. Jak rozumiem, rozszerzenie / przekierowanie z oficjalnego API Java 8 nigdy nie było celem projektowym wsparcia strumieniowego.
Sartorius
3
@Sartorius ma rację - polecam sprawdzić lustro Github w celu uzyskania szczegółowych informacji na temat użytkowania oraz referencje
LordParsley
Czytałem, że generalnie strumienie Java są wolniejsze niż kolekcje. stackoverflow.com/questions/22658322/… A co z tymi backportami?
Shikhar Shrivastav
12

Od wersji 8.2 DexGuard możliwe jest korzystanie z Java 8 strumieni API również na urządzeniach z systemem Android <poziom API 24. Aby to zrobić, trzeba zawierać streamsupport bibliotekę i DexGuard przełoży wszystkie Java 8 strumieniowych wywołań API do dostarczonego biblioteka. Nie jest wymagana żadna dodatkowa obsługa, a programiści mogą po prostu kodować za pomocą dostarczonego interfejsu API strumieni Java 8. Zależności są również tłumaczone automatycznie, więc możliwe jest wykorzystanie bibliotek z funkcjami Java 8 również do programowania na Androida.

Ta funkcja będzie również dostępna w ProGuard w najbliższej przyszłości, bądźcie czujni.

Edycja: Proguard 6.1.0, dla którego istnieje już wersja beta, obsługuje backportowanie strumieni Java 8 i API czasu.

T. Neidhart
źródło
to nie jest oficjalna biblioteka
użytkownik25
Nie mam pojęcia o samej bibliotece, ale radziłbym sprawdzić licencję biblioteki przed użyciem w komercyjnym projekcie. Powszechna Licencja Publiczna GNU, wersja 2, z wyjątkiem Classpath . Prawdopodobnie warstwa musi to potwierdzić.
Michał Harakal
5
@MichalHarakal zajęło mi kilka sekund, zanim zdałem sobie sprawę, że ta warstwa to tak naprawdę prawnik :)
superjos
6

Może być trochę za późno na imprezę, ale właśnie zobaczyłem, że jeśli użyjemy java8.util.stream.StreamSupport, możemy uruchomić to samo podejście do programowania funkcjonalnego i używać go przed Api 24. Np. Wzięte z web3j -

StreamSupport.stream(transactionReceipt.getLogs())
            .map(log -> extractEventParameters(event, log))
            .filter(Objects::nonNull)
            .collect(Collectors.toList());
Abhriya Roy
źródło
3
@AjahnCharles Mówienie ludziom, aby po prostu używali języka B, gdy ich pytanie dotyczy języka A, nie jest dobrą odpowiedzią. Wiele projektów wciąż jest napisanych w Javie.
mkuech
2
@AjahnCharles Dobrze jest zwrócić uwagę czytelników na ewentualne rozważenie zmian w ekosystemie Androida. To powiedziawszy, pytanie dotyczy konkretnej funkcji Javy, która nadal jest oficjalnie obsługiwanym językiem do programowania na Androida. Przełączanie się, nawet jeśli „tylko” hybrydyzuje aplikację, wiąże się z kosztami (krzywa uczenia się, być może ich zespół nie obsługuje tego itp.) I wymaga zagłębienia się w znacznie więcej niż to, o co pytano w pytaniu. Co ważniejsze, komentarz nie dotyczy tego, jak Kotlin jest rozwiązaniem, co sprawia, że ​​jest bardziej wyrwany z kontekstu i mniej pomocny.
mkuech
3
@AjahnCharles, kiedy jest to wyraźnie wymienione Java 8 Stream API, czuję, że odpowiedź powinna być również w JAVA!
Abhriya Roy
1

Tak, jest ! Począwszy od AGP 4.0.0 możemy używać Stream API i kilku innych API Java 8+ (np. java.time)

Minimalne wymagane zmiany w pliku build.gradle Twojej aplikacji :

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
źródło
-1

Innym rozwiązaniem, które lubię używać, jest statyczne używanie rozszerzeń Kotlina nad kolekcjami z kodu Java, jeśli projekt obsługuje oba oczywiście :

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

Sam dla .map, .reduce, .first, ... etc

y.allam
źródło
-6

Utwórz interfejs İnterface.

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

Utwórz metodę filtrowania.

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

Korzystanie z kodu

    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
źródło