JavaRush /Java blogi /Random-UZ /Java 8 xususiyatlari – Yakuniy qoʻllanma (2-qism)
0xFF
Daraja
Донецк

Java 8 xususiyatlari – Yakuniy qoʻllanma (2-qism)

Guruhda nashr etilgan
Maqola tarjimasining ikkinchi qismi Java 8 xususiyatlari – Yakuniy qoʻllanma . Birinchi qism bu erda (havola o'zgarishi mumkin). Java 8 xususiyatlari - Yakuniy qo'llanma (2-qism) - 1

5. Java 8 kutubxonalarida yangi funksiyalar

Java 8 zamonaviy parallellik, funktsional dasturlash, sana/vaqt va boshqalarni yaxshiroq qo'llab-quvvatlash uchun ko'plab yangi sinflarni qo'shdi va mavjudlarini kengaytirdi.

5.1. Sinf ixtiyoriy

Mashhur NullPointerException Java ilovalari nosozliklarining eng keng tarqalgan sababidir. Uzoq vaqt oldin Google-ning mukammal loyihasi GuavaOptional yechim sifatida taqdim etilgan NullPointerExceptionbo'lib, kodni null tekshiruvlar bilan ifloslanishini oldini oladi va natijada toza kod yozishni rag'batlantiradi. Google tomonidan ilhomlantirilgan Guava klassi Optionalendi Java 8 ning bir qismidir. OptionalBu shunchaki konteyner: unda qiymat yoki ba'zi turdagi bo'lishi mumkin Тyoki oddiygina null bo'lishi mumkin. U ko'plab foydali usullarni taqdim etadi, shuning uchun aniq null tekshiruvlar endi oqlanmaydi. Batafsil ma'lumot uchun rasmiy hujjatlarga qarang . Keling, foydalanishning ikkita kichik misolini ko'rib chiqaylik Optional: null bilan va holda.
Optional<String> fullName = Optional.ofNullable( null );
System.out.println( "Full Name is set? " + fullName.isPresent() );
System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) );
System.out.println( fullName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
Agar misol null bo'lmagan qiymatni o'z ichiga olgan bo'lsa, usul trueisPresent() qiymatini qaytaradi va aks holda noto'g'ri . Usul, agar u null bo'lsa, standart qiymatni yaratish uchun funktsiyalarni qabul qiladigan natijani qaytarish mexanizmini o'z ichiga oladi . map () usuli joriy qiymatni o'zgartiradi va yangi namunani qaytaradi . Usul ga o'xshaydi , lekin funksiya o'rniga u standart qiymatni oladi. Mana ushbu dasturning chiqishi: OptionalorElseGet()OptionalOptionalOptionalorElse()orElseGet()
Full Name is set? false
Full Name: [none]
Hey Stranger!
Keling, yana bir misolni tez ko'rib chiqaylik:
Optional<String> firstName = Optional.of( "Tom" );
System.out.println( "First Name is set? " + firstName.isPresent() );
System.out.println( "First Name: " + firstName.orElseGet( () -> "[none]" ) );
System.out.println( firstName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
System.out.println();
Natija shunday bo'ladi:
First Name is set? true
First Name: Tom
Hey Tom!
Batafsil ma'lumot uchun rasmiy hujjatlarga qarang .

5.2. Oqimlar

Yangi qo'shilgan Stream API ( java.util.stream) Java-da haqiqiy funktsional uslub dasturlashni taqdim etadi. Bu Java kutubxonasiga eng keng qamrovli qo'shimcha bo'lib, Java dasturchilariga sezilarli darajada samaraliroq bo'lish imkonini beradi va ularga samarali, toza va ixcham kod yaratish imkonini beradi. Stream API to'plamlarni qayta ishlashni ancha osonlashtiradi (lekin ular bilan cheklanmaydi, keyinroq ko'rib chiqamiz). Misol tariqasida oddiy sinfni olaylik Task.
public class Streams  {
    private enum Status {
        OPEN, CLOSED
    };

    private static final class Task {
        private final Status status;
        private final Integer points;

        Task( final Status status, final Integer points ) {
            this.status = status;
            this.points = points;
        }

        public Integer getPoints() {
            return points;
        }

        public Status getStatus() {
            return status;
        }

        @Override
        public String toString() {
            return String.format( "[%s, %d]", status, points );
        }
    }
}
Vazifada ba'zi nuqtalar (yoki psevdo-qiyinchiliklar) mavjud va OCHIQ yoki yopilishi mumkin . Keling, o'ynash uchun kichik muammolar to'plamini taqdim qilaylik.
final Collection<Task> tasks = Arrays.asList(
    new Task( Status.OPEN, 5 ),
    new Task( Status.OPEN, 13 ),
    new Task( Status.CLOSED, 8 )
);
Biz aniqlamoqchi bo'lgan birinchi savol - OPEN topshiriqlari hozirda nechta ballni o'z ichiga oladi? Java 8 dan oldin buning odatiy yechimi iteratordan foydalanish edi foreach. Ammo Java 8 da javob oqimlar: ketma-ket va parallel yig'ish operatsiyalarini qo'llab-quvvatlaydigan elementlar ketma-ketligi.
// Подсчет общего количества очков всех активных задач с использованием sum()
final long totalPointsOfOpenTasks = tasks
    .stream()
    .filter( task -> task.getStatus() == Status.OPEN )
    .mapToInt( Task::getPoints )
    .sum();

System.out.println( "Total points: " + totalPointsOfOpenTasks );
Va konsol chiqishi quyidagicha ko'rinadi:
Total points: 18
Keling, bu erda nima bo'layotganini ko'rib chiqaylik. Birinchidan, vazifalar to'plami oqimli tasvirga aylantiriladi. Operatsiya keyin barcha vazifalarni YOPIQfilter holati bilan filtrlaydi . Keyingi bosqichda operatsiya har bir misol uchun usul yordamida oqim s ni oqim s ga aylantiradi . Nihoyat, barcha fikrlar yakuniy natijani ta'minlaydigan usul yordamida yig'iladi . Keyingi misollarga o'tishdan oldin, yodda tutish kerak bo'lgan mavzular haqida ba'zi eslatmalar mavjud (batafsilroq ma'lumot bu erda ). Operatsiyalar oraliq va yakuniy operatsiyalarga bo'linadi . Oraliq operatsiyalar yangi oqimni qaytaradi. Ular har doim dangasa; kabi oraliq operatsiyalarni bajarishda ular aslida filtrlashni amalga oshirmaydilar, balki uning o'rniga yangi oqim yaratadilar, u tugallangach, berilgan predikatga mos keladigan dastlabki oqim elementlarini o'z ichiga oladi. Natija yoki yon ta'sirni yaratish uchun va kabi cheklangan operatsiyalar oqim orqali o'tkazilishi mumkin. Yakuniy operatsiya tugagandan so'ng, oqim ishlatilgan deb hisoblanadi va uni qayta ishlatib bo'lmaydi. Deyarli barcha holatlarda, yakuniy operatsiyalar asosiy ma'lumotlar manbai orqali o'tishni yakunlaydi. Iplarning yana bir qimmatli xususiyati qutidan tashqarida parallel jarayonlarni qo'llab-quvvatlashdir. Keling, barcha masalalarning ballari yig'indisini topadigan ushbu misolni ko'rib chiqaylik. mapToIntTaskIntegerTask::getPointsTasksumstreamfilterforEachsum
// Calculate total points of all tasks
final double totalPoints = tasks
   .stream()
   .parallel()
   .map( task -> task.getPoints() ) // or map( Task::getPoints )
   .reduce( 0, Integer::sum );

System.out.println( "Total points (all tasks): " + totalPoints );
Bu birinchi misolga juda o'xshaydi, faqat biz barcha vazifalarni parallel ravishda qayta ishlashga harakat qilamiz va usul yordamida yakuniy natijani hisoblaymiz reduce. Mana konsol chiqishi:
Total points (all tasks): 26.0
Ko'pincha elementlarni ma'lum bir mezon bo'yicha guruhlash zarurati mavjud. Misol iplar bunga qanday yordam berishi mumkinligini ko'rsatadi.
// Группировка задач по их статусу
final Map<Status, List<Task>> map = tasks
    .stream()
    .collect( Collectors.groupingBy( Task::getStatus ) );
System.out.println( map );
Konsol chiqishi quyidagicha bo'ladi:
{CLOSED=[[CLOSED, 8]], OPEN=[[OPEN, 5], [OPEN, 13]]}
Muammoli misollar bilan yakunlash uchun keling, jami ballar asosida to'plamdagi har bir muammoning umumiy foizini (yoki vaznini) hisoblab chiqamiz:
// Подсчет веса каждой задачи (How процент от общего количества очков)
final Collection<String> result = tasks
    .stream()                                        // Stream<String>
    .mapToInt( Task::getPoints )                     // IntStream
    .asLongStream()                                  // LongStream
    .mapToDouble( points -> points / totalPoints )   // DoubleStream
    .boxed()                                         // Stream<Double>
    .mapToLong( weigth -> ( long )( weigth * 100 ) ) // LongStream
    .mapToObj( percentage -> percentage + "%" )      // Stream<String>
    .collect( Collectors.toList() );                 // List<String>

System.out.println( result );
Konsol chiqishi quyidagicha bo'ladi:
[19%, 50%, 30%]
Va nihoyat, yuqorida aytib o'tganimizdek, Stream API faqat Java to'plamlari uchun emas. Matn fayllarini satr bo'yicha o'qish kabi odatiy kiritish-chiqarish operatsiyasi oqimni qayta ishlashdan foydalanish uchun juda yaxshi nomzoddir. Buni isbotlash uchun kichik bir misol.
final Path path = new File( filename ).toPath();
try( Stream<String> lines = Files.lines( path, StandardCharsets.UTF_8 ) ) {
    lines.onClose( () -> System.out.println("Done!") ).forEach( System.out::println );
}
onConsoleIpda chaqiriladigan usul qo'shimcha shaxsiy ishlov beruvchiga ega ekvivalent ipni qaytaradi. close()Xususiy ishlov beruvchi metod ipda chaqirilganda chaqiriladi . Stream API hamda lambdalar va mos yozuvlar usullari hamda Java 8 da standart va statik usullar zamonaviy dasturiy taʼminotni ishlab chiqish paradigmalariga javobdir. Batafsil ma'lumot uchun rasmiy hujjatlarga qarang .

5.3. Sana/vaqt API (JSR 310)

Java 8 yangi Sana va vaqt API (JSR 310) taqdim etish orqali sana va vaqtni boshqarishga yangi ko'rinish beradi . Sana va vaqtni manipulyatsiya qilish Java dasturchilari uchun eng og'ir nuqtalardan biridir. java.util.DateQuyidagi standart java.util.Calendarvaziyatni umuman yaxshilamadi (ehtimol uni yanada chalkashtirib yubordi). Joda-Time shunday tug'ildi: Java uchun ajoyib sana/vaqt API alternativasi . Java 8 (JSR 310) dagi yangi Sana/Vaqt API ga Joda-Time katta ta'sir ko'rsatadi va undan eng yaxshisini oladi. Yangi paket sana, vaqt, sana/vaqt, vaqt zonalari, davomiylik va vaqtni boshqarish uchun barcha sinflarnijava.time o'z ichiga oladi . API dizayni o'zgarmaslikni juda jiddiy qabul qildi: o'zgarishlarga yo'l qo'yilmaydi (dan qiyin saboq ). Agar o'zgartirish kerak bo'lsa, tegishli sinfning yangi nusxasi qaytariladi. Keling, asosiy sinflarni va ulardan foydalanish misollarini ko'rib chiqaylik. Birinchi sinf , vaqt mintaqasidan foydalangan holda joriy lahza, sana va vaqtga kirishni ta'minlaydi. va oʻrniga ishlatilishi mumkin . java.util.CalendarClockClockSystem.currentTimeMillis()TimeZone.getDefault()
// Получить системное время How смещение UTC
final Clock clock = Clock.systemUTC();
System.out.println( clock.instant() );
System.out.println( clock.millis() );
Konsol chiqishiga misol:
2014-04-12T15:19:29.282Z
1397315969360
Biz ko'rib chiqadigan boshqa yangi sinflar LocaleDateva LocalTime. LocaleDateISO-8601 kalendar tizimida faqat vaqt mintaqasisiz sana qismini o'z ichiga oladi. Shunga ko'ra, LocalTimeu vaqt kodining faqat bir qismini o'z ichiga oladi>.
// получить местную date и время время
final LocalDate date = LocalDate.now();
final LocalDate dateFromClock = LocalDate.now( clock );

System.out.println( date );
System.out.println( dateFromClock );

// получить местную date и время время
final LocalTime time = LocalTime.now();
final LocalTime timeFromClock = LocalTime.now( clock );

System.out.println( time );
System.out.println( timeFromClock );
Konsol chiqishiga misol:
2014-04-12
2014-04-12
11:25:54.568
15:25:54.568
LocalDateTimeISO-8601 kalendar tizimida sana va vaqtni birlashtiradi LocaleDateva va o'z ichiga oladi, lekin vaqt mintaqasi yo'q. LocalTimeQuyida oddiy misol keltirilgan.
// Get the local date/time
final LocalDateTime datetime = LocalDateTime.now();
final LocalDateTime datetimeFromClock = LocalDateTime.now( clock );

System.out.println( datetime );
System.out.println( datetimeFromClock );
Konsol chiqishiga misol:
2014-04-12T11:37:52.309
2014-04-12T15:37:52.309
Muayyan vaqt mintaqasi uchun sana/vaqt kerak bo'lsa, ZonedDateTime. U ISO-8601 kalendar tizimidagi sana va vaqtni o'z ichiga oladi. Turli vaqt zonalari uchun bir nechta misollar.
// Получение даты/времени для временной зоны
final ZonedDateTime zonedDatetime = ZonedDateTime.now();
final ZonedDateTime zonedDatetimeFromClock = ZonedDateTime.now( clock );
final ZonedDateTime zonedDatetimeFromZone = ZonedDateTime.now( ZoneId.of( "America/Los_Angeles" ) );

System.out.println( zonedDatetime );
System.out.println( zonedDatetimeFromClock );
System.out.println( zonedDatetimeFromZone );
Konsol chiqishiga misol:
2014-04-12T11:47:01.017-04:00[America/New_York]
2014-04-12T15:47:01.017Z
2014-04-12T08:47:01.017-07:00[America/Los_Angeles]
Va nihoyat, sinfni ko'rib chiqaylik Duration: soniya va nanosekundlarda vaqt oralig'i. Bu ikki sana o'rtasidagi hisobni juda oddiy qiladi. Keling, buni qanday qilishni ko'rib chiqaylik:
// Получаем разницу между двумя датами
final LocalDateTime from = LocalDateTime.of( 2014, Month.APRIL, 16, 0, 0, 0 );
final LocalDateTime to = LocalDateTime.of( 2015, Month.APRIL, 16, 23, 59, 59 );

final Duration duration = Duration.between( from, to );
System.out.println( "Duration in days: " + duration.toDays() );
System.out.println( "Duration in hours: " + duration.toHours() );
Yuqoridagi misol 2014-yil 16-aprel va 2015-yil 16-aprel ikki sana o‘rtasidagi davomiylikni (kun va soatlarda) hisoblab chiqadi . Mana konsol chiqishiga misol:
Duration in days: 365
Duration in hours: 8783
Java 8-dagi yangi sana/vaqt haqidagi umumiy taassurot juda va juda ijobiy. Qisman o'zgarishlar jangovar sinovdan o'tgan poydevorga (Joda-Time) asoslanganligi sababli, qisman bu safar masala jiddiy qayta ko'rib chiqilganligi va ishlab chiquvchilarning ovozi eshitilganligi sababli. Tafsilotlar uchun rasmiy hujjatlarga qarang .

5.4. Nashorn JavaScript dvigateli

Java 8 yangi Nashorn JavaScript dvigateli bilan birga keladi , bu sizga JVM da muayyan turdagi JavaScript ilovalarini ishlab chiqish va ishga tushirish imkonini beradi. Nashorn JavaScript dvigateli javax.script.ScriptEngine dasturining yana bir ilovasi boʻlib, Java va JavaScript-ning oʻzaro taʼsiriga ruxsat berish uchun bir xil qoidalar toʻplamiga amal qiladi. Mana, kichik bir misol.
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName( "JavaScript" );

System.out.println( engine.getClass().getName() );
System.out.println( "Result:" + engine.eval( "function f() { return 1; }; f() + 1;" ) );
Konsol chiqishiga misol:
jdk.nashorn.api.scripting.NashornScriptEngine
Result: 2

5.5. Baza 64

Nihoyat, Base64 kodlashni qo'llab-quvvatlash Java 8-ning chiqarilishi bilan Java standart kutubxonasiga o'z yo'lini topdi. Uni ishlatish juda oson, misol buni ko'rsatadi.
package com.javacodegeeks.java8.base64;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class Base64s {
    public static void main(String[] args) {
        final String text = "Base64 finally in Java 8!";

        final String encoded = Base64
            .getEncoder()
            .encodeToString( text.getBytes( StandardCharsets.UTF_8 ) );
        System.out.println( encoded );

        final String decoded = new String(
            Base64.getDecoder().decode( encoded ),
            StandardCharsets.UTF_8 );
        System.out.println( decoded );
    }
}
Dasturning konsol chiqishi ham kodlangan, ham dekodlangan matnni ko'rsatadi:
QmFzZTY0IGZpbmFsbHkgaW4gSmF2YSA4IQ==
Base64 finally in Java 8!
Shuningdek, URL-do'st kodlovchilar/dekoderlar, shuningdek, MIME-do'st kodlovchilar/dekoderlar ( Base64.getUrlEncoder()/ Base64.getUrlDecoder(), Base64.getMimeEncoder()/ Base64.getMimeDecoder()) uchun sinflar mavjud.

5.6. Parallel massivlar

Java 8 versiyasi parallel massivlarni qayta ishlash uchun ko'plab yangi usullarni qo'shadi. Ehtimol, ulardan eng muhimi parallelSort()ko'p yadroli mashinalarda saralashni sezilarli darajada tezlashtirishi mumkin. Quyidagi kichik misol yangi usullar oilasini ( parallelXxx) amalda ko'rsatadi.
package com.javacodegeeks.java8.parallel.arrays;

import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;

public class ParallelArrays {
    public static void main( String[] args ) {
        long[] arrayOfLong = new long [ 20000 ];

        Arrays.parallelSetAll( arrayOfLong,
            index -> ThreadLocalRandom.current().nextInt( 1000000 ) );
        Arrays.stream( arrayOfLong ).limit( 10 ).forEach(
            i -> System.out.print( i + " " ) );
        System.out.println();

        Arrays.parallelSort( arrayOfLong );
        Arrays.stream( arrayOfLong ).limit( 10 ).forEach(
            i -> System.out.print( i + " " ) );
        System.out.println();
    }
}
parallelSetAll()Ushbu kichik kod qismi 20 000 tasodifiy qiymatlar bilan massivni to'ldirish usulidan foydalanadi . Shundan so'ng u qo'llaniladi parallelSort(). Dastur massivning aslida tartiblanganligini ko'rsatish uchun tartiblashdan oldin va keyin dastlabki 10 ta elementni chop etadi. Misol dastur chiqishi quyidagicha ko'rinishi mumkin (massivning elementlari tasodifiy ekanligini unutmang).
Unsorted: 591217 891976 443951 424479 766825 351964 242997 642839 119108 552378
Sorted: 39 220 263 268 325 607 655 678 723 793

5.7. Parallellik

java.util.concurrent.ConcurrentHashMapYangi qo'shilgan oqim ob'ektlari va lambda ifodalari asosida jamlangan operatsiyalarni qo'llab-quvvatlash uchun sinfga yangi usullar qo'shildi . Bundan tashqari, umumiy birlashtirishni qo'llab-quvvatlash uchun sinfga yangi usullar qo'shildi java.util.concurrent.ForkJoinPool(shuningdek, Java parallelligi bo'yicha bepul kursimizga qarang ). O'qish/yozishni boshqarish uchun uchta kirish rejimi bilan qobiliyatga asoslangan qulflashni ta'minlash uchun yangi sinf java.util.concurrent.locks.StampedLockqo'shildi (u unchalik yaxshi bo'lmaganga yaxshiroq alternativ sifatida ko'rib chiqilishi mumkin java.util.concurrent.locks.ReadWriteLock). Paketga qo'shilgan yangi sinflar java.util.concurrent.atomic:
  • Ikkitomonlama akkumulyator
  • DoubleAdder
  • Uzoq akkumulyator
  • LongAdder

6. Java ish vaqti muhitidagi yangi xususiyatlar (JVM)

Hudud PermGeniste'foga chiqarildi va o'rniga Metaspace (JEP 122) o'rnatildi. JVM variantlari -XX:PermSizeva mos ravishda va -XX:MaxPermSizebilan almashtirildi . -XX:MetaSpaceSize-XX:MaxMetaspaceSize

7. Xulosa

Kelajak shu erda: Java 8 ishlab chiquvchilarga yanada samaraliroq bo'lishga imkon beruvchi xususiyatlarni taqdim etish orqali o'z platformasini oldinga siljitdi. Ishlab chiqarish tizimlarini Java 8 ga ko‘chirishga hali erta, biroq qabul qilish keyingi bir necha oy ichida asta-sekin o‘sib borishi kerak. Biroq, hozir Java 8 muvofiqligi uchun kod bazasini tayyorlashni boshlash va agar u etarlicha xavfsiz va barqaror bo'lsa, Java 8 o'zgarishlarini kiritishga tayyor bo'lish vaqti keldi. Jamiyatning Java 8-ni qabul qilganligidan dalolat sifatida, Pivotal yaqinda Java 8-ni ishlab chiqarishni qo'llab-quvvatlaydigan Spring Framework-ni chiqardi . Izohlarda Java 8 ning qiziqarli yangi funksiyalari haqida fikringizni bildirishingiz mumkin.

8. Manbalar

Java 8 xususiyatlarining turli jihatlarini chuqur muhokama qiladigan ba'zi qo'shimcha manbalar:
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION