JavaRush /Blog Java /Random-MS /Ciri Java 8 – Panduan Terbaik (Bahagian 1)
0xFF
Tahap
Донецк

Ciri Java 8 – Panduan Terbaik (Bahagian 1)

Diterbitkan dalam kumpulan
Bahagian pertama terjemahan artikel Java 8 Features – The ULTIMATE Guide . Bahagian kedua ada di sini (pautan mungkin berubah). Ciri Java 8 – Panduan Terbaik (Bahagian 1) - 1 Nota Editor : Artikel ini diterbitkan semasa Java 8 tersedia untuk umum dan semua petunjuk menunjukkan bahawa ini sememangnya versi utama. Di sini kami telah menyediakan panduan Java Code Geeks dengan banyaknya seperti Bermain dengan Java 8 – Lambdas dan Concurrency , Panduan API Tarikh dan Masa Java 8: LocalDateTime dan Kelas Abstrak lwn Antara Muka di Era Java 8 . Kami juga memautkan kepada 15 tutorial Java 8 yang mesti dibaca daripada sumber lain . Sudah tentu kita melihat beberapa kelemahan, seperti Sisi Gelap Java 8 . Jadi, sudah tiba masanya untuk mengumpulkan semua ciri utama Java 8 di satu tempat untuk kemudahan anda. Nikmati!

1. Pengenalan

Tidak dinafikan, keluaran Java 8 adalah acara terhebat sejak Java 5 (dikeluarkan agak lama dahulu, pada tahun 2004). Ia membawa banyak ciri baharu kepada Java dalam bahasa, pengkompil, perpustakaan, alatan dan JVM (Java Virtual Machine). Dalam tutorial ini, kita akan melihat perubahan ini dan menunjukkan kes penggunaan yang berbeza dengan contoh kehidupan sebenar. Panduan ini terdiri daripada beberapa bahagian, setiap satunya membincangkan aspek khusus platform:
  • Bahasa
  • Penyusun
  • Perpustakaan
  • Alatan
  • Persekitaran Masa Jalan (JVM)

2. Ciri baharu dalam Java 8

Walau apa pun, Java 8 adalah keluaran utama. Kita boleh mengatakan bahawa ia mengambil masa yang lama kerana pelaksanaan ciri yang dicari oleh setiap pembangun Java. Dalam bahagian ini kita akan membincangkan kebanyakannya.

2.1. Lambdas dan Antara Muka Fungsian

Lambdas (juga dikenali sebagai kaedah persendirian atau tanpa nama) ialah perubahan bahasa terbesar dan paling dinanti-nantikan dalam keseluruhan keluaran Java 8. Ia membenarkan kami menentukan kefungsian sebagai hujah kaedah (dengan mengisytiharkan fungsi di sekelilingnya), atau untuk menentukan kod sebagai data : konsep yang biasa digunakan oleh setiap pembangun fungsi. pengaturcaraan _ Banyak bahasa pada platform JVM (Groovy, Scala , ...) mempunyai lambda dari hari pertama, tetapi pembangun Java tidak mempunyai pilihan selain mewakili lambda melalui kelas tanpa nama. Perbahasan reka bentuk lambda mengambil banyak masa dan usaha awam. Tetapi akhirnya kompromi ditemui, yang membawa kepada kemunculan reka bentuk ringkas baru. Dalam bentuk yang paling mudah, lambda boleh diwakili sebagai senarai parameter yang dipisahkan koma, simbol –> dan badan. Sebagai contoh:
Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) )
Ambil perhatian bahawa jenis hujah e ditentukan oleh pengkompil. Selain itu, anda boleh menentukan secara eksplisit jenis parameter dengan membungkus parameter dalam kurungan. Sebagai contoh:
Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.println( e ) );
Sekiranya badan lambda lebih kompleks, ia boleh dibalut dengan pendakap kerinting, serupa dengan definisi fungsi biasa di Jawa. Sebagai contoh:
Arrays.asList( "a", "b", "d" ).forEach( e -< {
    System.out.print( e );
    System.out.print( e );
} );
Lambda boleh merujuk kepada ahli kelas dan pembolehubah setempat (secara tersirat menjadikan panggilan berkesan tanpa mengira sama ada finalmedan itu diakses atau tidak). Sebagai contoh, 2 coretan ini adalah bersamaan:
String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach(
    ( String e ) -> System.out.print( e + separator ) );
DAN:
final String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach(
    ( String e ) -> System.out.print( e + separator ) );
Lambdas boleh mengembalikan nilai. Jenis pulangan akan ditentukan oleh pengkompil. Pengisytiharan returntidak diperlukan jika badan lambda terdiri daripada satu baris. Dua coretan kod di bawah adalah setara:
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );
DAN:
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> {
    int result = e1.compareTo( e2 );
    return result;
} );
Pembangun bahasa berfikir untuk masa yang lama tentang cara menjadikan fungsi sedia ada mesra lambda. Akibatnya, konsep antara muka berfungsi muncul. Antara muka berfungsi ialah antara muka dengan hanya satu kaedah. Akibatnya, ia boleh ditukar secara tersirat kepada ungkapan lambda. java.lang.Runnabledan java.util.concurrent.Callabledua contoh hebat antara muka berfungsi. Dalam amalan, antara muka berfungsi sangat rapuh: jika seseorang menambah walaupun satu kaedah lain pada definisi antara muka, ia tidak akan berfungsi lagi dan proses penyusunan tidak akan selesai. Untuk mengelakkan kerapuhan ini dan mentakrifkan secara eksplisit maksud antara muka sebagai berfungsi, anotasi khas telah ditambahkan dalam Java 8 @FunctionalInterface(semua antara muka sedia ada dalam perpustakaan Java menerima anotasi @FunctionalInterface). Mari kita lihat definisi ringkas antara muka berfungsi ini:
@FunctionalInterface
public interface Functional {
    void method();
}
Terdapat satu perkara yang perlu diingat: kaedah lalai dan kaedah statik tidak melanggar prinsip antara muka berfungsi dan boleh diisytiharkan:
@FunctionalInterface
public interface FunctionalDefaultMethods {
    void method();

    default void defaultMethod() {
    }
}
Lambdas ialah ciri Java 8 yang paling popular. Mereka mempunyai semua potensi untuk menarik lebih ramai pembangun ke platform hebat ini dan menyediakan sokongan pintar untuk ciri dalam Java tulen. Untuk maklumat lebih terperinci, sila rujuk kepada dokumentasi rasmi .

2.2. Antara Muka Lalai dan Kaedah Statik

Java 8 mengembangkan definisi antara muka dengan dua konsep baharu: kaedah lalai dan kaedah statik. Kaedah lalai menjadikan antara muka agak serupa dengan ciri, tetapi berfungsi untuk tujuan yang sedikit berbeza. Ia membenarkan anda menambah kaedah baharu pada antara muka sedia ada tanpa memecahkan keserasian ke belakang untuk versi antara muka ini yang ditulis sebelum ini. Perbezaan antara kaedah lalai dan kaedah abstrak ialah kaedah abstrak mesti dilaksanakan manakala kaedah lalai tidak. Sebaliknya, setiap antara muka mesti menyediakan apa yang dipanggil pelaksanaan lalai, dan semua keturunan akan menerimanya secara lalai (dengan keupayaan untuk mengatasi pelaksanaan lalai ini jika perlu). Mari kita lihat contoh di bawah.
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";
    }
}
Antara muka Defaulablemengisytiharkan kaedah lalai notRequired()menggunakan kata kunci defaultsebagai sebahagian daripada definisi kaedah. Salah satu kelas, DefaultableImpl, melaksanakan antara muka ini meninggalkan kaedah lalai seperti sedia ada. Kelas lain, OverridableImpl, mengatasi pelaksanaan lalai dan menyediakan kelasnya sendiri. Satu lagi ciri menarik yang diperkenalkan dalam Java 8 ialah antara muka boleh mengisytiharkan (dan menawarkan pelaksanaan) kaedah statik. Berikut ialah contoh:
private interface DefaulableFactory {
    // Interfaces now allow static methods
    static Defaulable create( Supplier<Defaulable> supplier ) {
        return supplier.get();
    }
}
Sekeping kecil kod menggabungkan kaedah lalai dan kaedah statik daripada contoh di atas:
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() );
}
Output konsol program ini kelihatan seperti ini:
Default implementation
Overridden implementation
Pelaksanaan kaedah lalai dalam JVM adalah sangat cekap dan pemanggilan kaedah disokong oleh arahan bytecode. Kaedah lalai membenarkan antara muka Java sedia ada untuk berkembang tanpa melanggar proses penyusunan. Contoh yang baik ialah banyak kaedah yang ditambahkan pada antara muka java.util.Collection: stream(), parallelStream(), forEach(), removeIf(), ... Walaupun berkuasa, kaedah lalai harus digunakan dengan berhati-hati: sebelum mengisytiharkan kaedah lalai, anda harus berfikir dua kali sama ada ini benar-benar perlu kerana ini boleh menyebabkan untuk menyusun kekaburan dan ralat dalam hierarki yang kompleks. Untuk maklumat lebih terperinci, sila rujuk dokumentasi .

2.3. Kaedah Rujukan

Kaedah rujukan melaksanakan sintaks berguna untuk merujuk kaedah sedia ada atau pembina kelas atau objek Java (contoh). Bersama-sama dengan ungkapan lambda, kaedah rujukan menjadikan binaan bahasa padat dan ringkas, menjadikannya berasaskan templat. Di bawah ialah kelas Carsebagai contoh definisi kaedah yang berbeza, mari kita serlahkan empat jenis kaedah rujukan yang disokong:
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() );
    }
}
Kaedah rujukan pertama ialah rujukan kepada pembina dengan sintaks Class::newatau alternatif untuk generik Class< T >::new. Perhatikan bahawa pembina tidak mempunyai hujah.
final Car car = Car.create( Car::new );
final List<Car> cars = Arrays.asList( car );
Pilihan kedua ialah rujukan kepada kaedah statik dengan sintaks Class::static_method. Ambil perhatian bahawa kaedah mengambil tepat satu parameter jenis Car.
cars.forEach( Car::collide );
Jenis ketiga ialah rujukan kepada kaedah contoh objek arbitrari jenis tertentu dengan sintaks Class::method. Ambil perhatian bahawa tiada hujah diterima oleh kaedah.
cars.forEach( Car::repair );
Dan yang terakhir, jenis keempat ialah rujukan kepada kaedah contoh kelas tertentu dengan sintaks instance::method. Sila ambil perhatian bahawa kaedah hanya menerima satu parameter jenis Car.
final Car police = Car.create( Car::new );
cars.forEach( police::follow );
Menjalankan semua contoh ini sebagai program Java menghasilkan output konsol berikut (rujukan kelas Carmungkin berbeza-beza):
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
Untuk maklumat lebih terperinci dan butiran kaedah rujukan, sila rujuk kepada dokumentasi rasmi .

2.4. Anotasi pendua

Sejak Java 5 memperkenalkan sokongan untuk anotasi , ciri ini telah menjadi sangat popular dan digunakan secara meluas. Walau bagaimanapun, salah satu had penggunaan anotasi ialah fakta bahawa anotasi yang sama tidak boleh diisytiharkan lebih daripada sekali di tempat yang sama. Java 8 melanggar peraturan ini dan memperkenalkan anotasi pendua. Ini membolehkan anotasi yang sama diulang beberapa kali di lokasi di mana ia diisytiharkan. Anotasi pendua hendaklah menganotasi diri mereka sendiri menggunakan anotasi @Repeatable. Sebenarnya, ini bukanlah perubahan dalam bahasa kerana ia adalah helah pengkompil, manakala tekniknya tetap sama. Mari lihat contoh mudah:
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() );
        }
    }
}
Seperti yang dapat kita lihat, kelas Filterdianotasi dengan @Repeatable( Filters. class). Filtershanyalah pemilik anotasi Filter, tetapi pengkompil Java cuba menyembunyikan kehadiran mereka daripada pembangun. Oleh itu, antara muka Filterablemengandungi anotasi Filteryang diisytiharkan dua kali (tanpa menyebut Filters). Reflection API juga menyediakan kaedah baharu getAnnotationsByType()untuk mengembalikan anotasi pendua bagi beberapa jenis (ingat bahawa Boleh Ditapis. class.getAnnotation( Penapis. class) akan mengembalikan contoh yang disuntik pengkompil Filters). Output program akan kelihatan seperti ini:
filter1
filter2
Untuk maklumat lebih terperinci, sila rujuk kepada dokumentasi rasmi .

2.5. Inferens jenis dipertingkatkan

Pengkompil Java 8 telah menerima banyak penambahbaikan jenis inferens. Dalam kebanyakan kes, parameter jenis eksplisit boleh ditakrifkan oleh pengkompil, dengan itu menjadikan kod lebih bersih. Mari lihat satu contoh:
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;
    }
}
Dan inilah penggunaan dengan jenis 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() );
    }
}
Parameter jenis Value.defaultValue()ditentukan secara automatik dan tidak perlu diberikan secara eksplisit. Dalam Java 7, contoh yang sama tidak akan disusun dan mesti ditulis semula sebagai <NOBR>Value.<String>defaultValue()</NOBR>.

2.6. Sokongan anotasi dikembangkan

Java 8 mengembangkan konteks di mana anotasi boleh digunakan. Pada masa kini, hampir semua perkara boleh mempunyai anotasi: pembolehubah tempatan, jenis generik, superclass dan antara muka yang dilaksanakan, malah pengecualian kaedah. Beberapa contoh dibentangkan di bawah:
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_USEdan ElementType.TYPE_PARAMETERdua jenis elemen baharu untuk menerangkan konteks anotasi yang berkaitan. Annotation Processing APIjuga telah mengalami perubahan kecil untuk mengenali jenis anotasi baharu di Jawa.

3. Ciri baharu dalam pengkompil Java

3.1. Nama parameter

Sepanjang masa, pembangun Java telah mencipta pelbagai cara untuk menyimpan nama parameter kaedah dalam kod bait Java untuk menjadikannya tersedia pada masa jalan (contohnya, perpustakaan Paranamer ). Akhirnya, Java 8 mencipta fungsi sukar ini dalam bahasa (menggunakan Reflection API dan kaedah Parameter.getName()) dan bytecode (menggunakan hujah pengkompil baharu javac:) –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() );
        }
    }
}
Jika anda menyusun kelas ini tanpa menggunakan hujah –parametersdan kemudian menjalankan program, anda akan melihat sesuatu seperti ini:
Parameter: arg0
Dengan parameter –parametersyang diserahkan kepada pengkompil, output program akan berbeza (nama sebenar parameter akan ditunjukkan):
Parameter: args
Untuk pengguna Maven lanjutan, hujah –parameters boleh ditambah pada kompilasi menggunakan bahagian 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>
Untuk menyemak ketersediaan nama parameter terdapat isNamePresent()kaedah mudah yang disediakan oleh kelas Parameter.

4. Alat Java Baharu

Java 8 dilengkapi dengan set alat baris arahan baharu. Dalam bahagian ini kita akan melihat yang paling menarik daripada mereka.

4.1. Enjin Nashorn: jjs

jjs ialah enjin Nashorn kendiri yang berasaskan baris arahan. Ia memerlukan senarai fail kod sumber JavaScript dan menjalankannya. Sebagai contoh, mari buat fail func.js dengan kandungan berikut:
function f() {
     return 1;
};

print( f() + 1 );
Untuk menjalankan fail ini mari kita berikannya sebagai hujah kepada jjs :
jjs func.js
Output konsol akan menjadi seperti ini:
2
Untuk butiran lanjut lihat dokumentasi .

4.2. Penganalisis Ketergantungan Kelas: jdeps

jdeps ialah alat baris arahan yang sangat hebat. Ia menunjukkan kebergantungan peringkat pakej atau kelas untuk kelas Java. Ia menerima fail .class , folder atau fail JAR sebagai input. Secara lalai , jdeps mengeluarkan kebergantungan kepada output standard (konsol). Sebagai contoh, mari lihat laporan pergantungan perpustakaan Rangka Kerja Spring yang popular . Untuk memastikan contoh pendek, mari lihat kebergantungan untuk fail JAR sahaja org.springframework.core-3.0.5.RELEASE.jar.
jdeps org.springframework.core-3.0.5.RELEASE.jar
Arahan ini mengeluarkan agak banyak, jadi kami hanya akan menganalisis sebahagian daripada output. Ketergantungan dikumpulkan mengikut pakej. Jika tiada kebergantungan, tidak dijumpai akan dipaparkan .
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
Untuk maklumat lebih terperinci, sila rujuk kepada dokumentasi rasmi .
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION