เป็นไปได้ไหมที่จะใช้ 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

มีใครรู้วิธีแก้ปัญหาบ้างไหม?


3
ไม่คุณไม่สามารถใช้สตรีม java ด้านล่าง api 24 มีไลบรารีของบุคคลที่สามที่ใช้สิ่งเดียวกันแม้ว่าจะทำงานนั้น
tyczj

1
ฉันมีห้องสมุดขนาดเล็กที่ทำสิ่งที่คล้ายกันสำหรับ apis ที่ต่ำกว่า: github.com/smaspe/FunctionalIterables
njzk2

2
ดูstackoverflow.com/questions/39265004/…และstackoverflow.com/questions/39039566/…สำหรับคำถามที่คล้ายกัน (และคำตอบ)
Sartorius

3
@PEMapModder คุณสามารถใช้นิพจน์แลมบ์ดาและการอ้างอิงเมธอดโดยใช้คอมไพเลอร์ Jack ใหม่ที่กำหนดเป้าหมายไปที่ Android จนถึง Gingerbread สิ่งที่คุณไม่มีภายใต้ SDK 24 คือเมธอดอินเทอร์เฟซเริ่มต้น / สแตติกและ API เฉพาะ Java 8 เช่น Stream API
Sartorius

คุณสามารถใช้ระดับ StreamSupport ภายใต้ API 24
ÖzerÖzcan

คำตอบ:


71

[คำตอบเดิม]

คุณไม่สามารถใช้สตรีม 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 toolchain ในการใช้อินเทอร์เฟซเริ่มต้นและวิธีการแบบคงที่ในขอบเขตไฟล์ Jar นอกจากนี้ยังมีลิงก์ไปยัง android-retroXXX อื่น ๆ เช่นสำหรับ CompletableFuture

[อัปเดต aeracode 2020-07-24]

ข่าวดีตอนนี้เราสามารถใช้ Java 8 กระแส API และมากขึ้นโดยไม่ต้องมีระดับต่ำสุด API


9
ในขณะที่SolidและLightweight-Stream-APIเป็นตัวเลือกที่มีค่าอย่างแน่นอนสำหรับการเขียนโปรแกรมแบบสตรีม แต่ IMHO ไม่มีตัวเลือกใดที่สามารถถือเป็น "แบ็คพอร์ต" ของ Java 8 Stream API จากระยะไกลได้ เพียงโครงการที่ฉันรู้ว่าสามารถเรียกร้องให้ใกล้ชิดในไวยากรณ์และที่ตราไว้ในการทำงานเพื่อ Java 8 ลำธารเป็นstreamsupport ตัวอย่างเช่นรองรับสตรีมคู่ขนานด้วย แม้ว่าสิ่งนี้อาจไม่สำคัญสำหรับนักพัฒนา Android
Sartorius

IMO น้ำหนักเบาสตรีม-API เป็นที่อร่อยที่สุดบน Android เพราะการสนับสนุน Gradle และเพิ่มความพิเศษเช่น "ให้เลือก", "groupBy" ฯลฯgithub.com/aNNiMON/Lightweight-Stream-API#additional-operators
LordParsley

2
@LordParsley streamsupport ยังมีการสนับสนุน Gradle สำหรับความพิเศษนั่นเป็นเรื่องจริง ตามที่ฉันเข้าใจแล้วการขยาย / เปลี่ยนเส้นทางจาก Java 8 API อย่างเป็นทางการไม่เคยเป็นเป้าหมายการออกแบบของการสนับสนุนสตรีม
Sartorius

3
@Sartorius ถูกต้อง - ฉันขอแนะนำให้ตรวจสอบกระจก Github สำหรับรายละเอียดการใช้งานและ Gradle refs github.com/streamsupport/streamsupport
LordParsley

ฉันได้อ่านว่าโดยทั่วไป Java Streams จะช้ากว่าคอลเลกชัน stackoverflow.com/questions/22658322/… backport อะไรประมาณนี้
Shikhar Shrivastav

12

ตั้งแต่รุ่น 8.2 ของDexGuardมันเป็นไปได้ที่จะใช้ Java 8 ลำธาร API ยังบนอุปกรณ์ Android <ระดับ API 24. เพื่อที่จะทำเช่นนั้นหนึ่งในความต้องการที่จะรวมstreamsupportห้องสมุดและ DexGuard จะแปล Java ทั้งหมด 8 กระแส API โทรไปที่มีให้ ห้องสมุด. ไม่จำเป็นต้องมีการจัดการเพิ่มเติมและนักพัฒนาสามารถเขียนโค้ดโดยใช้ Java 8 stream API ที่มีให้ การอ้างอิงจะถูกแปลโดยอัตโนมัติดังนั้นจึงเป็นไปได้ที่จะใช้ไลบรารีที่มีคุณสมบัติ Java 8 สำหรับการพัฒนา Android

ฟีเจอร์นี้จะรวมอยู่ใน ProGuard ในอนาคตอันใกล้โปรดอดใจรอ

แก้ไข: Proguard 6.1.0 ซึ่งมีอยู่แล้วรุ่นเบต้ารองรับ backporting Java 8 stream และ time API


ไม่ใช่ห้องสมุดอย่างเป็นทางการ
25

ฉันไม่รู้จริงๆเกี่ยวกับห้องสมุด แต่ฉันอยากแนะนำให้ตรวจสอบใบอนุญาตของห้องสมุดก่อนที่จะใช้ในโครงการเชิงพาณิชย์ ใบอนุญาตสาธารณะทั่วไปรุ่นที่ 2 กับข้อยกเว้น อาจมีเลเยอร์เพื่อยืนยัน
Michal Harakal

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 ไม่ใช่คำตอบที่ดี หลายโครงการยังคงเขียนด้วยภาษาจาวา
mkuech

2
@AjahnCharles คุณทำให้เป็นจุดที่ดีเกี่ยวกับการดึงดูดความสนใจของผู้อ่านที่จะอาจจะมีการเปลี่ยนแปลงในการพิจารณาระบบนิเวศ Android คำถามดังกล่าวเกี่ยวกับคุณลักษณะเฉพาะของ Java ซึ่งยังคงเป็นภาษาที่รองรับอย่างเป็นทางการสำหรับการพัฒนา Android การเปลี่ยนแม้ว่าแอปของคุณจะ "เพียง" ไฮบริด "เท่านั้น แต่ก็ทำให้เสียค่าใช้จ่าย (ช่วงการเรียนรู้บางทีทีมของพวกเขาอาจไม่สนับสนุน ฯลฯ ) และนั่นต้องใช้วิธีการที่มากกว่าสิ่งที่ถูกถามในคำถาม ที่สำคัญกว่านั้นความคิดเห็นไม่ได้กล่าวถึงวิธีการที่ Kotlin เป็นวิธีแก้ปัญหาซึ่งทำให้ไม่อยู่ในบริบทและมีประโยชน์น้อยลง
mkuech

3
@AjahnCharles เมื่อพูดถึงอย่างชัดเจนJava 8 Stream APIฉันรู้สึกว่าคำตอบควรอยู่ใน JAVA ด้วย!
Abhriya Roy

2

ใช่แล้ว ! เริ่มจาก AGP 4.0.0 เราสามารถใช้ Stream API และ Java 8+ API อื่น ๆ (เช่น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, ... ฯลฯ


-5

สร้างอินเตอร์เฟส

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"));
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.