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

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

Guruhda nashr etilgan
Maqola tarjimasining birinchi qismi Java 8 Xususiyatlari – ULTIMATE Guide . Ikkinchi qism bu erda (havola o'zgarishi mumkin). Java 8 xususiyatlari - Yakuniy qo'llanma (1-qism) - 1 Tahrirlovchining eslatmasi : Ushbu maqola Java 8 omma uchun mavjud bo'lgan paytda nashr etilgan va barcha ko'rsatkichlar bu haqiqatan ham asosiy versiya ekanligini ko'rsatadi. Bu yerda biz Java 8 bilan oʻynash – Lambdas va parallellik , Java 8 Sana va vaqt API qoʻllanmasi: LocalDateTime va Abstract Class va Java 8 Era interfeysi kabi koʻplab Java Code Geeks qoʻllanmalarini taqdim etdik . Shuningdek, biz boshqa manbalardan o'qilishi kerak bo'lgan 15 ta Java 8 darsliklariga havola qilamiz . Albatta, biz Java 8 ning qorong'u tomoni kabi ba'zi kamchiliklarni ko'rib chiqamiz . Shunday qilib, sizga qulaylik uchun Java 8 ning barcha asosiy xususiyatlarini bir joyda to'plash vaqti keldi. Rohatlaning!

1.Kirish

Shubhasiz, Java 8-ning chiqarilishi Java 5-dan keyingi eng katta voqeadir (juda uzoq vaqt oldin, 2004 yilda chiqarilgan). U Java-ga tilda, kompilyatorda, kutubxonalarda, asboblarda va JVM (Java Virtual Machine) kabi ko'plab yangi xususiyatlarni keltirdi. Ushbu qo'llanmada biz ushbu o'zgarishlarni ko'rib chiqamiz va turli xil foydalanish holatlarini hayotiy misollar bilan ko'rsatamiz. Qo'llanma bir nechta qismlardan iborat bo'lib, ularning har biri platformaning o'ziga xos tomonini ko'rib chiqadi:
  • Til
  • Kompilyator
  • Kutubxonalar
  • Asboblar
  • Ish vaqti muhiti (JVM)

2. Java 8 da yangi funksiyalar

Har holda, Java 8 asosiy versiyadir. Aytishimiz mumkinki, har bir Java dasturchisi izlayotgan xususiyatlarni amalga oshirish juda uzoq davom etdi. Ushbu bo'limda biz ularning ko'pchiligini ko'rib chiqamiz.

2.1. Lambdalar va funktsional interfeyslar

Lambdalar (shuningdek, shaxsiy yoki anonim usullar sifatida ham tanilgan) Java 8-ning butun versiyasidagi eng katta va eng kutilgan til o'zgarishidir. Ular bizga funksionallikni metod argumenti sifatida belgilashga (uning atrofida funktsiyani e'lon qilish orqali) yoki kodni ma'lumotlar sifatida ko'rsatishga imkon beradi. : har bir ishlab chiquvchiga tanish bo'lgan tushunchalar . dasturlash _ JVM platformasidagi ko'plab tillarda (Groovy, Scala , ...) birinchi kundan boshlab lambdalar mavjud edi, ammo Java ishlab chiquvchilari lambdalarni anonim sinflar orqali ifodalashdan boshqa iloji yo'q edi. Lambdalar dizaynini muhokama qilish jamoatchilikdan ko'p vaqt va kuch talab qildi. Ammo oxir-oqibat murosalar topildi, bu esa yangi ixcham dizaynlarning paydo bo'lishiga olib keldi. Eng oddiy shaklda lambda vergul bilan ajratilgan parametrlar roʻyxati, –> belgisi va tana sifatida koʻrsatilishi mumkin. Masalan:
Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) )
E'tibor bering, e argumentining turi kompilyator tomonidan belgilanadi. Bundan tashqari, siz parametrni qavslar ichiga o'rash orqali parametr turini aniq belgilashingiz mumkin. Masalan:
Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.println( e ) );
Agar lambda tanasi murakkabroq bo'lsa, uni Java'dagi oddiy funksiya ta'rifiga o'xshash jingalak qavslarga o'rash mumkin. Masalan:
Arrays.asList( "a", "b", "d" ).forEach( e -< {
    System.out.print( e );
    System.out.print( e );
} );
finalLambda sinf a'zolariga va mahalliy o'zgaruvchilarga murojaat qilishi mumkin ( maydonga kirish yoki yo'qligidan qat'i nazar, qo'ng'iroqni bevosita samarali qiladi ). Misol uchun, bu 2 parcha ekvivalentdir:
String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach(
    ( String e ) -> System.out.print( e + separator ) );
VA:
final String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach(
    ( String e ) -> System.out.print( e + separator ) );
Lambdalar qiymatni qaytarishi mumkin. Qaytish turi kompilyator tomonidan aniqlanadi. returnAgar lambda tanasi bitta chiziqdan iborat bo'lsa, deklaratsiya talab qilinmaydi. Quyidagi ikkita kod parchasi ekvivalentdir:
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );
VA:
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> {
    int result = e1.compareTo( e2 );
    return result;
} );
Tilni ishlab chiquvchilar uzoq vaqt davomida mavjud funktsiyalarni lambda uchun qulay qilish haqida o'ylashdi. Natijada, funktsional interfeys tushunchasi paydo bo'ldi. Funktsional interfeys faqat bitta usulga ega interfeysdir. Natijada, uni bilvosita lambda ifodasiga aylantirish mumkin. java.lang.Runnableva java.util.concurrent.Callablefunktsional interfeyslarning ikkita ajoyib namunasi. Amalda, funktsional interfeyslar juda nozik: agar kimdir interfeys ta'rifiga hatto bitta boshqa usulni qo'shsa, u endi funksional bo'lmaydi va kompilyatsiya jarayoni tugamaydi. Ushbu mo'rtlikning oldini olish va interfeysning maqsadini funktsional sifatida aniq belgilash uchun Java 8-ga maxsus izoh qo'shildi @FunctionalInterface(Java kutubxonasidagi barcha mavjud interfeyslar @FunctionalInterface izohini oldi). Keling, funktsional interfeysning oddiy ta'rifini ko'rib chiqaylik:
@FunctionalInterface
public interface Functional {
    void method();
}
Bir narsani yodda tutish kerak: standart usullar va statik usullar funktsional interfeys printsipini buzmaydi va e'lon qilinishi mumkin:
@FunctionalInterface
public interface FunctionalDefaultMethods {
    void method();

    default void defaultMethod() {
    }
}
Lambdalar Java 8 ning eng mashhur xususiyatidir. Ular ushbu ajoyib platformaga ko'proq ishlab chiquvchilarni jalb qilish va sof Java-dagi xususiyatlarni aqlli qo'llab-quvvatlash uchun barcha imkoniyatlarga ega. Batafsil ma'lumot uchun rasmiy hujjatlarga qarang .

2.2. Standart interfeyslar va statik usullar

Java 8 interfeyslar ta'rifini ikkita yangi tushuncha bilan kengaytirdi: standart usul va statik usul. Standart usullar interfeyslarni belgilarga biroz o'xshash qiladi, lekin biroz boshqacha maqsadga xizmat qiladi. Ular ushbu interfeyslarning ilgari yozilgan versiyalari uchun orqaga qarab muvofiqlikni buzmasdan mavjud interfeyslarga yangi usullarni qo'shish imkonini beradi. Standart usullar va mavhum usullar o'rtasidagi farq shundaki, mavhum usullar amalga oshirilishi kerak, ammo standart usullar mavjud emas. Buning o'rniga, har bir interfeys standart dastur deb ataladigan narsani ta'minlashi kerak va barcha avlodlar uni sukut bo'yicha qabul qilishadi (agar kerak bo'lsa, ushbu standart dasturni bekor qilish imkoniyati bilan). Keling, quyidagi misolni ko'rib chiqaylik.
private interface Defaulable {
    // Интерфейсы теперь разрешают методы по умолчанию,
    // клиент может реализовывать  (переопределять)
    // or не реализовывать его
    default String notRequired() {
        return "Default implementation";
    }
}

private static class DefaultableImpl implements Defaulable {
}

private static class OverridableImpl implements Defaulable {
    @Override
    public String notRequired() {
        return "Overridden implementation";
    }
}
Interfeys usul ta'rifining bir qismi sifatida kalit so'z yordamida Defaulablestandart usulni e'lon qiladi . Sinflardan biri, , standart usulni qoldirib, ushbu interfeysni amalga oshiradi. Boshqa sinf, , standart amalga oshirishni bekor qiladi va o'zini ta'minlaydi. Java 8-da taqdim etilgan yana bir qiziqarli xususiyat shundaki, interfeyslar statik usullarni e'lon qilishi (va ularni amalga oshirishni taklif qilishi) mumkin. Mana bir misol: notRequired()defaultDefaultableImplOverridableImpl
private interface DefaulableFactory {
    // Interfaces now allow static methods
    static Defaulable create( Supplier<Defaulable> supplier ) {
        return supplier.get();
    }
}
Kichik kod qismi yuqoridagi misoldagi standart usul va statik usulni birlashtiradi:
public static void main( String[] args ) {
    Defaulable defaulable = DefaulableFactory.create( DefaultableImpl::new );
    System.out.println( defaulable.notRequired() );

    defaulable = DefaulableFactory.create( OverridableImpl::new );
    System.out.println( defaulable.notRequired() );
}
Ushbu dasturning konsol chiqishi quyidagicha ko'rinadi:
Default implementation
Overridden implementation
JVM-da standart usulni amalga oshirish juda samarali va usulni chaqirish bayt-kod ko'rsatmalari bilan qo'llab-quvvatlanadi. Standart usullar mavjud Java interfeyslarini kompilyatsiya jarayonini buzmasdan rivojlantirishga imkon berdi. Yaxshi misollar - interfeysga qo'shilgan ko'plab usullar java.util.Collection: stream(), parallelStream(), forEach(), removeIf(), ... Garchi kuchli bo'lsa-da, standart usullardan ehtiyotkorlik bilan foydalanish kerak: standart usulni e'lon qilishdan oldin, bu haqiqatan ham zarurmi yoki yo'qligini ikki marta o'ylab ko'rishingiz kerak, chunki bu sabab bo'lishi mumkin. murakkab ierarxiyalardagi noaniqliklar va xatolarni kompilyatsiya qilish. Batafsil ma'lumot olish uchun hujjatlarga qarang .

2.3. Malumot usullari

Yo'naltiruvchi usullar mavjud usullarga yoki Java sinflari yoki ob'ektlari (namsalari) konstruktorlariga murojaat qilish uchun foydali sintaksisni amalga oshiradi. Lambda iboralari bilan birgalikda mos yozuvlar usullari til konstruksiyalarini ixcham va ixcham qilib, uni shablonga asoslangan qiladi. Quyida turli metod ta'riflariga misol sifatida sinf berilgan Car, keling, mos yozuvlar usullarining to'rtta qo'llab-quvvatlanadigan turini ajratib ko'rsatamiz:
public static class Car {
    public static Car create( final Supplier<Car> supplier ) {
        return supplier.get();
    }

    public static void collide( final Car car ) {
        System.out.println( "Collided " + car.toString() );
    }

    public void follow( final Car another ) {
        System.out.println( "Following the " + another.toString() );
    }

    public void repair() {
        System.out.println( "Repaired " + this.toString() );
    }
}
Birinchi mos yozuvlar usuli sintaksisi bo'lgan konstruktorga havola Class::newyoki generiklar uchun muqobildir Class< T >::new. E'tibor bering, konstruktorda argumentlar yo'q.
final Car car = Car.create( Car::new );
final List<Car> cars = Arrays.asList( car );
Ikkinchi variant - sintaksis bilan statik usulga havola Class::static_method. E'tibor bering, usul aniq bir turdagi parametrni oladi Car.
cars.forEach( Car::collide );
Uchinchi tur - sintaksis bilan ma'lum turdagi ixtiyoriy ob'ektning namunasi usuliga havola Class::method. Usul tomonidan hech qanday argumentlar qabul qilinmasligini unutmang.
cars.forEach( Car::repair );
Va oxirgi, to'rtinchi tur - sintaksis bilan ma'lum bir sinf misolining usuliga havola instance::method. E'tibor bering, usul faqat bitta turdagi parametrni qabul qiladi Car.
final Car police = Car.create( Car::new );
cars.forEach( police::follow );
Ushbu misollarning barchasini Java dasturlari sifatida ishga tushirish quyidagi konsol natijasini beradi (sinf ma'lumotnomasi Carfarq qilishi mumkin):
Collided com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
Repaired com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
Following the com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
Batafsil ma'lumot va mos yozuvlar usullari haqida batafsil ma'lumot olish uchun rasmiy hujjatlarga qarang .

2.4. Ikki nusxadagi izohlar

Java 5 izohlarni qo'llab-quvvatlashni joriy qilganligi sababli , bu xususiyat juda mashhur va juda keng qo'llaniladi. Biroq, annotatsiyalardan foydalanishdagi cheklovlardan biri shundaki, bir xil izohni bir joyda bir necha marta e'lon qilish mumkin emas. Java 8 bu qoidani buzadi va takroriy izohlarni kiritadi. Bu bir xil izohlarni ular e'lon qilingan joyda bir necha marta takrorlash imkonini beradi. Takroriy izohlar izoh yordamida o'zini izohlashi kerak @Repeatable. Aslida, bu tilning o'zgarishi emas, balki kompilyatorning hiyla-nayrangidir, ammo texnika bir xil bo'lib qoladi. Keling, oddiy misolni ko'rib chiqaylik:
package com.javacodegeeks.java8.repeatable.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class RepeatingAnnotations {
    @Target( ElementType.TYPE )
    @Retention( RetentionPolicy.RUNTIME )
    public @interface Filters {
        Filter[] value();
    }

    @Target( ElementType.TYPE )
    @Retention( RetentionPolicy.RUNTIME )
    @Repeatable( Filters.class )
    public @interface Filter {
        String value();
    };

    @Filter( "filter1" )
    @Filter( "filter2" )
    public interface Filterable {
    }

    public static void main(String[] args) {
        for( Filter filter: Filterable.class.getAnnotationsByType( Filter.class ) ) {
            System.out.println( filter.value() );
        }
    }
}
Ko'rib turganimizdek, sinf @Repeatable ( Filtrlar ) Filterbilan izohlanadi . oddiygina izohlarning egasidir , lekin Java kompilyatori ularning mavjudligini ishlab chiquvchilardan yashirishga harakat qiladi. Shunday qilib, interfeys ikki marta e'lon qilingan izohlarni o'z ichiga oladi (eslatmasiz ). Reflection API shuningdek, ba'zi turdagi takroriy izohlarni qaytarishning yangi usulini taqdim etadi (esda tutingki, Filterable. .getAnnotation( Filtrlar. ) kompilyator tomonidan kiritilgan misolni qaytaradi ). Dasturning chiqishi quyidagicha ko'rinadi: classFiltersFilterFilterableFilterFiltersgetAnnotationsByType()classclassFilters
filter1
filter2
Batafsil ma'lumot uchun rasmiy hujjatlarga qarang .

2.5. Yaxshilangan turdagi xulosa

Java 8 kompilyatori ko'plab turdagi xulosalarni yaxshilashga erishdi. Ko'pgina hollarda, aniq turdagi parametrlar kompilyator tomonidan aniqlanishi mumkin va shu bilan kodni tozalaydi. Keling, bitta misolni ko'rib chiqaylik:
package com.javacodegeeks.java8.type.inference;

public class Value<T> {
    public static<T> T defaultValue() {
        return null;
    }

    public T getOrDefault( T value, T defaultValue ) {
        return ( value != null ) ? value : defaultValue;
    }
}
Va bu erda type bilan foydalanish Value<String>:
package com.javacodegeeks.java8.type.inference;

public class TypeInference {
    public static void main(String[] args) {
        final Value<String> value = new Value<>();
        value.getOrDefault( "22", Value.defaultValue() );
    }
}
Tur parametri Value.defaultValue()avtomatik ravishda aniqlanadi va uni aniq ko'rsatish shart emas. Java 7 da bir xil misol kompilyatsiya qilinmaydi va uni <NOBR>Value.<String>defaultValue()</NOBR> sifatida qayta yozish kerak.

2.6. Kengaytirilgan izohni qo'llab-quvvatlash

Java 8 izohlardan foydalanish mumkin bo'lgan kontekstni kengaytiradi. Hozirgi kunda deyarli hamma narsa izohga ega bo'lishi mumkin: mahalliy o'zgaruvchilar, umumiy turlar, superklasslar va amalga oshirilgan interfeyslar, hatto usul istisnolari. Quyida bir nechta misollar keltirilgan:
package com.javacodegeeks.java8.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Collection;

public class Annotations {
    @Retention( RetentionPolicy.RUNTIME )
    @Target( { ElementType.TYPE_USE, ElementType.TYPE_PARAMETER } )
    public @interface NonEmpty {
    }

    public static class Holder<@NonEmpty T> extends @NonEmpty Object {
        public void method() throws @NonEmpty Exception {
        }
    }

    @SuppressWarnings( "unused" )
    public static void main(String[] args) {
        final Holder<String> holder = new @NonEmpty Holder<String>();
        @NonEmpty Collection<@NonEmpty String> strings = new ArrayList<>();
    }
}
ElementType.TYPE_USEva ElementType.TYPE_PARAMETERtegishli izoh kontekstini tavsiflash uchun ikkita yangi element turi. Annotation Processing APIJava-da yangi izoh turlarini tanib olish uchun kichik o'zgarishlar ham amalga oshirildi.

3. Java kompilyatoridagi yangi funksiyalar

3.1. Parametr nomlari

Vaqt o'tishi bilan Java ishlab chiquvchilari metod parametr nomlarini Java baytekodida saqlashning turli usullarini ixtiro qilishdi, ularni ish vaqtida foydalanish mumkin (masalan, Paranamer kutubxonasi ). Nihoyat, Java 8 ushbu qiyin funktsiyani tilda (Reflection API va usuli yordamida Parameter.getName()) va baytekodda (yangi kompilyator argumentidan foydalangan holda javac:) yaratadi –parameters.
package com.javacodegeeks.java8.parameter.names;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class ParameterNames {
    public static void main(String[] args) throws Exception {
        Method method = ParameterNames.class.getMethod( "main", String[].class );
        for( final Parameter parameter: method.getParameters() ) {
            System.out.println( "Parameter: " + parameter.getName() );
        }
    }
}
Agar siz ushbu sinfni argumentdan foydalanmasdan kompilyatsiya qilsangiz –parametersva dasturni ishga tushirsangiz, siz shunday narsani ko'rasiz:
Parameter: arg0
Parametr –parameterskompilyatorga uzatilganda, dastur chiqishi boshqacha bo'ladi (parametrning haqiqiy nomi ko'rsatiladi):
Parameter: args
Ilg'or Maven foydalanuvchilari uchun -parameters argumentini kompilyatsiyaga bo'lim yordamida qo'shish mumkin maven-compiler-plugin:
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <configuration>
    <compilerArgument>-parameters</compilerArgument>
    <source>1.8</source>
    <target>1.8</target>
    </configuration>
</plugin>
Parametr nomlarining mavjudligini tekshirish uchun isNamePresent()sinf tomonidan taqdim etilgan qulay usul mavjud Parameter.

4. Yangi Java vositalari

Java 8 yangi buyruq qatori vositalari bilan birga keladi. Ushbu bo'limda biz ulardan eng qiziqarlilarini ko'rib chiqamiz.

4.1. Nashorn dvigateli: jjs

jjs - bu buyruq qatoriga asoslangan mustaqil Nashorn dvigatelidir. U JavaScript manba kodi fayllari ro'yxatini oladi va ularni ishga tushiradi. Masalan, quyidagi tarkibga ega func.js faylini yaratamiz :
function f() {
     return 1;
};

print( f() + 1 );
Ushbu faylni ishga tushirish uchun uni jjs ga argument sifatida topshiramiz :
jjs func.js
Konsol chiqishi quyidagicha bo'ladi:
2
Qo'shimcha ma'lumot olish uchun hujjatlarga qarang .

4.2. Sinfga bog'liqlik tahlilchisi: jdeps

jdeps - bu juda ajoyib buyruq qatori vositasi. U Java sinflari uchun paket yoki sinf darajasidagi bog'liqliklarni ko'rsatadi. U kirish sifatida .class fayl, papka yoki JAR faylni qabul qiladi. Odatiy bo'lib , jdeps bog'liqliklarni standart chiqishga (konsol) chiqaradi. Misol sifatida, keling, mashhur Spring Framework kutubxonasining bog'liqlik hisobotini ko'rib chiqaylik . Misolni qisqa tutish uchun keling, faqat JAR fayliga bog'liqliklarni ko'rib chiqaylik org.springframework.core-3.0.5.RELEASE.jar.
jdeps org.springframework.core-3.0.5.RELEASE.jar
Ushbu buyruq juda ko'p natijalar beradi, shuning uchun biz chiqishning faqat bir qismini tahlil qilamiz. Bog'liqlar paketlar bo'yicha guruhlangan. Agar bog'liqliklar bo'lmasa, topilmadi ko'rsatiladi .
org.springframework.core-3.0.5.RELEASE.jar -> C:\Program Files\Java\jdk1.8.0\jre\lib\rt.jar
   org.springframework.core (org.springframework.core-3.0.5.RELEASE.jar)
      -> java.io
      -> java.lang
      -> java.lang.annotation
      -> java.lang.ref
      -> java.lang.reflect
      -> java.util
      -> java.util.concurrent
      -> org.apache.commons.logging                         not found
      -> org.springframework.asm                            not found
      -> org.springframework.asm.commons                    not found
   org.springframework.core.annotation (org.springframework.core-3.0.5.RELEASE.jar)
      -> java.lang
      -> java.lang.annotation
      -> java.lang.reflect
      -> java.util
Batafsil ma'lumot uchun rasmiy hujjatlarga qarang .
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION