JavaRush /Java Blogu /Random-AZ /Java 8 Xüsusiyyətləri – Ən Yaxşı Bələdçi (1-ci Hissə)
0xFF
Səviyyə
Донецк

Java 8 Xüsusiyyətləri – Ən Yaxşı Bələdçi (1-ci Hissə)

Qrupda dərc edilmişdir
Java 8 Features – ULTIMATE Guide məqaləsinin tərcüməsinin birinci hissəsi . İkinci hissə buradadır (link dəyişə bilər). Java 8 Xüsusiyyətləri – Ən Yaxşı Bələdçi (1-ci Hissə) - 1 Redaktorun qeydi : Bu məqalə Java 8 ictimaiyyət üçün əlçatan olarkən dərc edilib və bütün əlamətlər bunun həqiqətən əsas versiya olduğunu göstərir. Burada Java 8 ilə oynamaq – Lambdalar və Parametrlər , Java 8 Tarix və Saat API Bələdçisi: LocalDateTimeJava 8 Dövründəki Abstract Sinif ilə müqayisədə çoxlu Java Code Geeks bələdçiləri təqdim etdik . Biz həmçinin digər mənbələrdən oxunmalı olan 15 Java 8 dərsliyi ilə əlaqə saxlayırıq . Əlbəttə ki, Java 8-in qaranlıq tərəfi kimi bəzi mənfi cəhətlərə baxırıq . Beləliklə, rahatlığınız üçün Java 8-in bütün əsas xüsusiyyətlərini bir yerdə toplamağın vaxtıdır. Zövq alın!

1. Giriş

Şübhəsiz ki, Java 8-in buraxılması Java 5-dən sonra ən böyük hadisədir (çox uzun müddət əvvəl, 2004-cü ildə buraxılmışdır). O, Java-ya həm dildə, həm tərtibçidə, kitabxanalarda, alətlərdə, həm də JVM-də (Java Virtual Maşın) bir çox yeni xüsusiyyətlər gətirdi. Bu dərslikdə biz bu dəyişikliklərə nəzər salacağıq və real həyat nümunələri ilə fərqli istifadə hallarını nümayiş etdirəcəyik. Təlimat bir neçə hissədən ibarətdir ki, onların hər biri platformanın xüsusi aspektinə toxunur:
  • Dil
  • Kompilyator
  • Kitabxanalar
  • Alətlər
  • Runtime Environment (JVM)

2. Java 8-də yeni funksiyalar

Hər halda, Java 8 əsas buraxılışdır. Hər bir Java tərtibatçısının axtardığı xüsusiyyətlərin həyata keçirilməsinə görə bu qədər uzun sürdüyünü deyə bilərik. Bu bölmədə biz onların əksəriyyətini əhatə edəcəyik.

2.1. Lambdalar və Funksional İnterfeyslər

Lambdalar (həmçinin şəxsi və ya anonim metodlar kimi tanınır) bütün Java 8 buraxılışında ən böyük və ən çox gözlənilən dil dəyişikliyidir. Onlar bizə funksionallığı metod arqumenti kimi təyin etməyə (ətrafında funksiya elan etməklə) və ya kodu məlumat kimi təyin etməyə imkan verir. : hər bir funksionallıq tərtibatçısının tanış olduğu anlayışlar . proqramlaşdırma _ JVM platformasındakı bir çox dildə (Groovy, Scala , ...) ilk gündən lambdalar var idi, lakin Java tərtibatçılarının lambdaları anonim siniflər vasitəsilə təmsil etməkdən başqa çarəsi yox idi. Lambdaların dizaynını müzakirə etmək ictimaiyyətdən çox vaxt və səy tələb etdi. Ancaq nəticədə kompromislər tapıldı, bu da yeni qısa dizaynların yaranmasına səbəb oldu. Ən sadə formada lambda vergüllə ayrılmış parametrlər siyahısı, a –> simvolu və gövdə kimi təqdim edilə bilər. Misal üçün:
Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) )
Qeyd edək ki, e arqumentinin tipi kompilyator tərəfindən müəyyən edilir. Əlavə olaraq, parametri mötərizə içərisində bükərək parametrin növünü açıq şəkildə təyin edə bilərsiniz. Misal üçün:
Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.println( e ) );
Lambda gövdəsi daha mürəkkəbdirsə, Java-dakı adi funksiya tərifinə bənzər qıvrımlı mötərizələrə bükülə bilər. Misal üçün:
Arrays.asList( "a", "b", "d" ).forEach( e -< {
    System.out.print( e );
    System.out.print( e );
} );
finalLambda sinif üzvlərinə və yerli dəyişənlərə istinad edə bilər ( sahəyə daxil olub-olmamasından asılı olmayaraq zəngi təsirli edir ). Məsələn, bu 2 parça ekvivalentdir:
String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach(
    ( String e ) -> System.out.print( e + separator ) );
VƏ:
final String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach(
    ( String e ) -> System.out.print( e + separator ) );
Lambdalar dəyər qaytara bilər. Qaytarma növü kompilyator tərəfindən müəyyən ediləcək. returnLambdanın gövdəsi bir sətirdən ibarətdirsə, bəyannamə tələb olunmur. Aşağıdakı iki kod parçası ekvivalentdir:
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );
VƏ:
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> {
    int result = e1.compareTo( e2 );
    return result;
} );
Dil tərtibatçıları uzun müddət mövcud funksiyaları lambdaya uyğunlaşdırmaq barədə fikirləşdilər. Nəticədə funksional interfeys anlayışı yarandı. Funksional interfeys yalnız bir metodu olan interfeysdir. Nəticə olaraq, o, dolayısı ilə lambda ifadəsinə çevrilə bilər. java.lang.Runnablejava.util.concurrent.Callablefunksional interfeyslərin iki böyük nümunəsi. Praktikada funksional interfeyslər çox kövrəkdir: əgər kimsə interfeys tərifinə hətta bir başqa metod əlavə etsə, o, artıq funksional olmayacaq və tərtib prosesi başa çatmayacaq. Bu kövrəkliyin qarşısını almaq və interfeysin məqsədini funksional olaraq açıq şəkildə müəyyən etmək üçün Java 8-də xüsusi annotasiya əlavə edildi @FunctionalInterface(Java kitabxanasındakı bütün mövcud interfeyslər @FunctionalInterface annotasiyasını aldı). Funksional interfeysin bu sadə tərifinə baxaq:
@FunctionalInterface
public interface Functional {
    void method();
}
Yadda saxlamaq lazım olan bir şey var: standart metodlar və statik metodlar funksional interfeys prinsipini pozmur və elan edilə bilər:
@FunctionalInterface
public interface FunctionalDefaultMethods {
    void method();

    default void defaultMethod() {
    }
}
Lambdalar Java 8-in ən populyar xüsusiyyətidir. Onlar bu gözəl platformaya daha çox tərtibatçı cəlb etmək və təmiz Java-da funksiyalar üçün ağıllı dəstək vermək üçün bütün potensiala malikdirlər. Daha ətraflı məlumat üçün rəsmi sənədlərə müraciət edin .

2.2. Defolt İnterfeyslər və Statik Metodlar

Java 8 interfeyslərin tərifini iki yeni anlayışla genişləndirdi: standart metod və statik metod. Defolt üsullar interfeysləri əlamətlərə bir qədər bənzədir, lakin bir az fərqli məqsədə xidmət edir. Onlar bu interfeyslərin əvvəllər yazılmış versiyaları üçün geriyə uyğunluğu pozmadan mövcud interfeyslərə yeni metodlar əlavə etməyə imkan verir. Defolt metodlarla mücərrəd metodlar arasındakı fərq ondan ibarətdir ki, defolt metodlar tətbiq edilmədiyi halda mücərrəd metodlar həyata keçirilməlidir. Bunun əvəzinə, hər bir interfeys sözdə defolt tətbiqetməni təmin etməlidir və bütün nəsillər onu standart olaraq alacaqlar (lazım olduqda bu defolt tətbiqi ləğv etmək imkanı ilə). Aşağıdakı nümunəyə baxaq.
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";
    }
}
İnterfeys metodun tərifinin bir hissəsi kimi açar sözdən istifadə edərək Defaulabledefolt metodu elan edir . Siniflərdən biri, , bu interfeysi standart metodu olduğu kimi buraxaraq həyata keçirir. Başqa bir sinif, , standart tətbiqi ləğv edir və özünü təmin edir. Java 8-də təqdim edilən digər maraqlı xüsusiyyət odur ki, interfeyslər statik metodları elan edə (və onların həyata keçirilməsini təklif edə bilər). Budur bir nümunə: notRequired()defaultDefaultableImplOverridableImpl
private interface DefaulableFactory {
    // Interfaces now allow static methods
    static Defaulable create( Supplier<Defaulable> supplier ) {
        return supplier.get();
    }
}
Kiçik bir kod parçası yuxarıdakı misaldakı standart metodu və statik metodu birləşdirir:
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() );
}
Bu proqramın konsol çıxışı belə görünür:
Default implementation
Overridden implementation
JVM-də standart metodun tətbiqi çox səmərəlidir və metod çağırışı bayt kodu təlimatları ilə dəstəklənir. Defolt üsullar mövcud Java interfeyslərinin tərtib prosesini pozmadan təkamül etməyə imkan verdi. Yaxşı nümunələr interfeysə əlavə edilən bir çox metodlardır java.util.Collection: stream(), parallelStream(), forEach(), removeIf(), ... Güclü olmasına baxmayaraq, defolt metodlar ehtiyatla istifadə edilməlidir: defolt metodu elan etməzdən əvvəl bunun həqiqətən zəruri olub-olmadığı barədə iki dəfə düşünməlisiniz, çünki bu, nəticə verə bilər. mürəkkəb iyerarxiyalarda qeyri-müəyyənlikləri və səhvləri tərtib etmək. Daha ətraflı məlumat üçün sənədlərə müraciət edin .

2.3. İstinad Metodları

İstinad metodları Java siniflərinin və ya obyektlərinin (nümunələrinin) mövcud metodlarına və ya konstruktorlarına istinad etmək üçün faydalı sintaksisi həyata keçirir. Lambda ifadələri ilə birlikdə istinad metodları dil konstruksiyalarını yığcam və yığcam edir, onu şablon əsaslı edir. Aşağıda Carmüxtəlif metod təriflərinə nümunə kimi bir sinif verilmişdir, gəlin dörd dəstəklənən istinad metodunu vurğulayaq:
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() );
    }
}
Class::newBirinci istinad metodu sintaksisi olan konstruktora və ya generiklər üçün alternativə istinaddır Class< T >::new. Qeyd edək ki, konstruktorun heç bir arqumenti yoxdur.
final Car car = Car.create( Car::new );
final List<Car> cars = Arrays.asList( car );
İkinci seçim sintaksis ilə statik metoda istinaddır Class::static_method. Qeyd edək ki, metod tam olaraq bir tip parametrini götürür Car.
cars.forEach( Car::collide );
Üçüncü növ sintaksis ilə müəyyən bir növ ixtiyari obyektin nümunəsinin metoduna istinaddır Class::method. Qeyd edək ki, metod tərəfindən heç bir arqument qəbul edilmir.
cars.forEach( Car::repair );
Və sonuncu, dördüncü növ sintaksis ilə müəyyən bir sinif nümunəsinin metoduna istinaddır instance::method. Nəzərə alın ki, metod yalnız bir növ parametri qəbul edir Car.
final Car police = Car.create( Car::new );
cars.forEach( police::follow );
Bütün bu nümunələri Java proqramları kimi işlətmək aşağıdakı konsol çıxışını verir (sinif istinadı Cardəyişə bilər):
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
Daha ətraflı məlumat və istinad metodlarının təfərrüatları üçün rəsmi sənədlərə müraciət edin .

2.4. Dublikat annotasiyalar

Java 5 qeydlər üçün dəstək təqdim etdiyindən bu xüsusiyyət çox populyarlaşdı və çox geniş istifadə edildi. Bununla belə, annotasiyalardan istifadənin məhdudiyyətlərindən biri o idi ki, eyni annotasiya eyni yerdə bir dəfədən çox elan edilə bilməz. Java 8 bu qaydanı pozur və dublikat annotasiyalar təqdim edir. Bu, eyni annotasiyaların elan edildiyi yerdə bir neçə dəfə təkrarlanmasına imkan verir. Dublikat annotasiyalar annotasiyadan istifadə edərək özlərini qeyd etməlidirlər @Repeatable. Əslində, bu, dildə dəyişiklik deyil, tərtibçi hiyləsidir, texnika eyni olaraq qalır. Sadə bir misala baxaq:
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() );
        }
    }
}
Gördüyümüz kimi, sinif @Repeatable ( Filtrlər ) Filterilə şərh olunur . sadəcə annotasiyaların sahibidir , lakin Java tərtibçisi onların mövcudluğunu tərtibatçılardan gizlətməyə çalışır. Beləliklə, interfeys iki dəfə elan edilən annotasiyaları ehtiva edir ( qeyd etmədən ). Reflection API həmçinin bəzi növ dublikat annotasiyaları qaytarmaq üçün yeni üsul təqdim edir (yadda saxlayın ki, Filtr edilə bilən. .getAnnotation( Filtrlər. ) kompilyator tərəfindən vurulmuş nümunəni qaytaracaq ). Proqramın çıxışı belə görünəcək: classFiltersFilterFilterableFilterFiltersgetAnnotationsByType()classclassFilters
filter1
filter2
Daha ətraflı məlumat üçün rəsmi sənədlərə müraciət edin .

2.5. Təkmilləşdirilmiş növ nəticə

Java 8 kompilyatoru bir çox növ nəticə çıxarma təkmilləşdirmələri aldı. Bir çox hallarda, açıq tip parametrləri kompilyator tərəfindən müəyyən edilə bilər və bununla da kodu daha təmiz edir. Bir misala baxaq:
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;
    }
}
Və burada növü ilə istifadə olunur 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() );
    }
}
Tip parametri Value.defaultValue()avtomatik olaraq müəyyən edilir və açıq şəkildə təqdim edilməsinə ehtiyac yoxdur. Java 7-də eyni nümunə tərtib edilməyəcək və <NOBR>Dəyər.<String>defaultValue()</NOBR> kimi yenidən yazılmalıdır.

2.6. Genişləndirilmiş annotasiya dəstəyi

Java 8 annotasiyaların istifadə oluna biləcəyi konteksti genişləndirir. İndiki vaxtda demək olar ki, hər şeyin annotasiyası ola bilər: yerli dəyişənlər, ümumi növlər, supersiniflər və həyata keçirilən interfeyslər, hətta metod istisnaları. Bir neçə nümunə aşağıda təqdim olunur:
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_USEElementType.TYPE_PARAMETERmüvafiq annotasiya kontekstini təsvir etmək üçün iki yeni element növü. Annotation Processing APIJava-da yeni annotasiya növlərini tanımaq üçün kiçik dəyişikliklərə də məruz qalmışdır.

3. Java kompilyatorunda yeni funksiyalar

3.1. Parametr adları

Bütün müddət ərzində Java tərtibatçıları metod parametr adlarını Java bayt kodunda saxlamağın müxtəlif yollarını icad etdilər ki, onları iş vaxtında əlçatan etsinlər (məsələn, Paranamer kitabxanası ). Nəhayət, Java 8 bu çətin funksiyanı dildə (Reflection API və metodundan istifadə etməklə Parameter.getName()) və bayt kodunda (yeni kompilyator arqumentindən istifadə etməklə javac:) yaradır –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() );
        }
    }
}
Bu sinfi arqumentdən istifadə etmədən tərtib etsəniz –parametersvə proqramı işə salsanız, belə bir şey görəcəksiniz:
Parameter: arg0
–parametersKompilyatora ötürülən parametrlə proqramın çıxışı fərqli olacaq (parametrin faktiki adı göstəriləcək):
Parameter: args
Qabaqcıl Maven istifadəçiləri üçün bölmədən istifadə edərək kompilyasiyaya –parameters arqumenti əlavə edilə bilər 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 adlarının mövcudluğunu yoxlamaq üçün isNamePresent()sinif tərəfindən təmin edilən əlverişli üsul var Parameter.

4. Yeni Java Alətləri

Java 8 yeni komanda xətti alətləri dəsti ilə gəlir. Bu bölmədə onlardan ən maraqlılarına baxacağıq.

4.1. Nashorn mühərriki: jjs

jjs , komanda xəttinə əsaslanan müstəqil Nashorn mühərrikidir. JavaScript mənbə kodu fayllarının siyahısını götürür və onları işə salır. Məsələn, aşağıdakı məzmunlu func.js faylı yaradaq :
function f() {
     return 1;
};

print( f() + 1 );
Bu faylı işə salmaq üçün onu jjs -ə arqument kimi ötürək :
jjs func.js
Konsol çıxışı belə olacaq:
2
Daha ətraflı məlumat üçün sənədlərə baxın .

4.2. Sinif Asılılıq Analizatoru: jdeps

jdeps həqiqətən əla komanda xətti alətidir. Java sinifləri üçün paket və ya sinif səviyyəsindən asılılıqları göstərir. O, giriş kimi .class faylı, qovluq və ya JAR faylını qəbul edir . Varsayılan olaraq , jdeps asılılıqları standart çıxışa (konsol) çıxarır. Nümunə olaraq məşhur Spring Framework kitabxanasının asılılıq hesabatına baxaq . Məsələni qısa tutmaq üçün gəlin yalnız JAR faylı üçün asılılıqlara baxaq org.springframework.core-3.0.5.RELEASE.jar.
jdeps org.springframework.core-3.0.5.RELEASE.jar
Bu əmr kifayət qədər çox nəticə verir, ona görə də çıxışın yalnız bir hissəsini təhlil edəcəyik. Asılılıqlar paketlərə görə qruplaşdırılır. Heç bir asılılıq yoxdursa, tapılmadı göstərilir .
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
Daha ətraflı məlumat üçün rəsmi sənədlərə müraciət edin .
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION