JavaRush /Java Blog /Random-TL /Mga Tampok ng Java 8 – Ang Pinakamahusay na Gabay (Bahagi...
0xFF
Antas
Донецк

Mga Tampok ng Java 8 – Ang Pinakamahusay na Gabay (Bahagi 1)

Nai-publish sa grupo
Ang unang bahagi ng pagsasalin ng artikulong Java 8 Features – The ULTIMATE Guide . Ang pangalawang bahagi ay narito (maaaring magbago ang link). Mga Tampok ng Java 8 – Ang Ultimate Guide (Bahagi 1) - 1 Tala ng Editor : Ang artikulong ito ay nai-publish habang ang Java 8 ay magagamit sa publiko at lahat ng mga indikasyon ay ito ay talagang isang pangunahing bersyon. Dito ay nagbigay kami ng mga gabay sa Java Code Geeks na sagana tulad ng Paglalaro sa Java 8 – Lambdas at Concurrency , Java 8 Date and Time API Guide: LocalDateTime at Abstract Class vs. Interface sa Java 8 Era . Nagli-link din kami sa 15 na dapat basahin na mga tutorial sa Java 8 mula sa iba pang mga mapagkukunan . Siyempre tinitingnan namin ang ilan sa mga downside, tulad ng Dark Side ng Java 8 . Kaya, oras na upang kolektahin ang lahat ng mga pangunahing tampok ng Java 8 sa isang lugar para sa iyong kaginhawahan. Enjoy!

1. Panimula

Walang pag-aalinlangan, ang paglabas ng Java 8 ay ang pinakadakilang kaganapan mula noong Java 5 (matagal nang inilabas, noong 2004). Nagdala ito ng maraming bagong feature sa Java kapwa sa wika, compiler, library, tool at JVM (Java Virtual Machine). Sa tutorial na ito, titingnan natin ang mga pagbabagong ito at magpapakita ng iba't ibang mga kaso ng paggamit na may mga tunay na halimbawa sa buhay. Ang gabay ay binubuo ng ilang bahagi, na ang bawat isa ay tumutugon sa isang partikular na aspeto ng platform:
  • Wika
  • Compiler
  • Mga aklatan
  • Mga gamit
  • Runtime Environment (JVM)

2. Mga bagong feature sa Java 8

Sa anumang kaso, ang Java 8 ay isang pangunahing paglabas. Masasabi nating natagalan ito dahil sa pagpapatupad ng mga tampok na hinahanap ng bawat developer ng Java. Sa seksyong ito ay tatalakayin natin ang karamihan sa mga ito.

2.1. Mga Lambdas at Functional na Interface

Ang Lambdas (kilala rin bilang pribado o anonymous na mga pamamaraan) ay ang pinakamalaki at pinaka-inaasahang pagbabago ng wika sa buong release ng Java 8. Nagbibigay-daan sila sa amin na tukuyin ang functionality bilang argumento ng method (sa pamamagitan ng pagdedeklara ng function sa paligid nito), o tukuyin ang code bilang data : mga konsepto na pamilyar sa bawat developer ng functionality. programming _ Maraming mga wika sa platform ng JVM (Groovy, Scala , ...) ay may mga lambda mula sa unang araw, ngunit ang mga developer ng Java ay walang pagpipilian kundi ang kumatawan sa mga lambda sa pamamagitan ng mga hindi kilalang klase. Ang debate sa disenyo ng lambda ay tumagal ng maraming pampublikong oras at pagsisikap. Ngunit kalaunan ay natagpuan ang mga kompromiso, na humantong sa paglitaw ng mga bagong maigsi na disenyo. Sa pinakasimpleng anyo nito, ang isang lambda ay maaaring katawanin bilang isang listahan ng mga parameter na pinaghihiwalay ng kuwit, isang –> simbolo , at isang katawan. Halimbawa:
Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) )
Tandaan na ang uri ng argument e ay tinutukoy ng compiler. Bukod pa rito, maaari mong tahasang tukuyin ang uri ng isang parameter sa pamamagitan ng pagbabalot ng parameter sa mga panaklong. Halimbawa:
Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.println( e ) );
Kung sakaling mas kumplikado ang katawan ng lambda, maaari itong balutin ng mga kulot na brace, katulad ng isang karaniwang kahulugan ng function sa Java. Halimbawa:
Arrays.asList( "a", "b", "d" ).forEach( e -< {
    System.out.print( e );
    System.out.print( e );
} );
Ang isang lambda ay maaaring sumangguni sa mga miyembro ng klase at mga lokal na variable (implicitly making the call effective regardless of if finalthe field is accessed or not). Halimbawa, ang 2 snippet na ito ay katumbas:
String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach(
    ( String e ) -> System.out.print( e + separator ) );
AT:
final String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach(
    ( String e ) -> System.out.print( e + separator ) );
Maaaring magbalik ng halaga ang Lambdas. Ang uri ng pagbabalik ay tutukuyin ng compiler. returnHindi kinakailangan ang isang deklarasyon kung ang katawan ng lambda ay binubuo ng isang linya. Ang dalawang snippet ng code sa ibaba ay katumbas:
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );
AT:
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> {
    int result = e1.compareTo( e2 );
    return result;
} );
Ang mga developer ng wika ay nag-isip nang mahabang panahon tungkol sa kung paano gawing lambda-friendly ang mga umiiral na function. Bilang resulta, lumitaw ang konsepto ng isang functional na interface. Ang functional na interface ay isang interface na may isang paraan lamang. Bilang resulta, maaari itong implicit na ma-convert sa isang lambda expression. java.lang.Runnableat java.util.concurrent.Callabledalawang magagandang halimbawa ng mga functional na interface. Sa pagsasagawa, ang mga functional na interface ay napakarupok: kung may nagdagdag ng kahit isa pang paraan sa kahulugan ng interface, hindi na ito gagana at hindi makukumpleto ang proseso ng compilation. Upang maiwasan ang pagkasira na ito at tahasang tukuyin ang layunin ng isang interface bilang functional, isang espesyal na anotasyon ang idinagdag sa Java 8 @FunctionalInterface(lahat ng umiiral na mga interface sa Java library ay nakatanggap ng @FunctionalInterface annotation). Tingnan natin ang simpleng kahulugan na ito ng isang functional na interface:
@FunctionalInterface
public interface Functional {
    void method();
}
Mayroong isang bagay na dapat tandaan: ang mga default na pamamaraan at mga static na pamamaraan ay hindi lumalabag sa prinsipyo ng isang functional na interface at maaaring ideklara:
@FunctionalInterface
public interface FunctionalDefaultMethods {
    void method();

    default void defaultMethod() {
    }
}
Ang Lambdas ay ang pinakasikat na feature ng Java 8. Mayroon silang lahat ng potensyal na makaakit ng higit pang mga developer sa napakagandang platform na ito at magbigay ng matalinong suporta para sa mga feature sa purong Java. Para sa mas detalyadong impormasyon, mangyaring sumangguni sa opisyal na dokumentasyon .

2.2. Mga Default na Interface at Static na Paraan

Pinalawak ng Java 8 ang kahulugan ng mga interface na may dalawang bagong konsepto: default na pamamaraan at static na pamamaraan. Ang mga default na pamamaraan ay gumagawa ng mga interface na medyo katulad ng mga katangian, ngunit nagsisilbi sa isang bahagyang naiibang layunin. Nagbibigay-daan sa iyo ang mga ito na magdagdag ng mga bagong pamamaraan sa mga umiiral nang interface nang hindi sinisira ang backward compatibility para sa mga dating nakasulat na bersyon ng mga interface na ito. Ang pagkakaiba sa pagitan ng mga default na pamamaraan at abstract na pamamaraan ay ang mga abstract na pamamaraan ay dapat ipatupad habang ang mga default na pamamaraan ay hindi. Sa halip, ang bawat interface ay dapat magbigay ng tinatawag na default na pagpapatupad, at lahat ng mga inapo ay makakatanggap nito bilang default (na may kakayahang i-override ang default na pagpapatupad na ito kung kinakailangan). Tingnan natin ang halimbawa sa ibaba.
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";
    }
}
Ang interface Defaulableay nagdedeklara ng isang default na paraan notRequired()gamit ang isang keyword defaultbilang bahagi ng kahulugan ng pamamaraan. Ang isa sa mga klase, DefaultableImpl, ay nagpapatupad ng interface na ito na iniiwan ang default na paraan kung ano ang dati. Ino-override ng isa pang klase, OverridableImpl, ang default na pagpapatupad at nagbibigay ng sarili nito. Ang isa pang kawili-wiling tampok na ipinakilala sa Java 8 ay ang mga interface ay maaaring magpahayag (at mag-alok ng mga pagpapatupad ng) mga static na pamamaraan. Narito ang isang halimbawa:
private interface DefaulableFactory {
    // Interfaces now allow static methods
    static Defaulable create( Supplier<Defaulable> supplier ) {
        return supplier.get();
    }
}
Pinagsasama ng isang maliit na piraso ng code ang default na pamamaraan at ang static na pamamaraan mula sa halimbawa sa itaas:
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() );
}
Ang console output ng program na ito ay ganito ang hitsura:
Default implementation
Overridden implementation
Ang pagpapatupad ng default na paraan sa JVM ay napakahusay at ang paraan ng invocation ay sinusuportahan ng mga tagubilin ng bytecode. Pinahintulutan ng mga default na pamamaraan ang mga umiiral nang Java interface na mag-evolve nang hindi sinisira ang proseso ng compilation. Ang mga magagandang halimbawa ay ang maraming mga pamamaraan na idinagdag sa interface java.util.Collection: stream(), parallelStream(), forEach(), removeIf(), ... Bagama't makapangyarihan, ang mga default na pamamaraan ay dapat gamitin nang may pag-iingat: bago magdeklara ng default na paraan, dapat mong pag-isipan nang dalawang beses kung ito ay talagang kinakailangan dahil ito ay maaaring humantong sa pagsasama-sama ng mga kalabuan at pagkakamali sa mga kumplikadong hierarchy. Para sa mas detalyadong impormasyon, mangyaring sumangguni sa dokumentasyon .

2.3. Mga pamamaraan ng sanggunian

Ang mga pamamaraan ng sanggunian ay nagpapatupad ng kapaki-pakinabang na syntax upang i-reference ang mga umiiral na pamamaraan o mga constructor ng mga klase o object ng Java (mga pagkakataon). Kasama ng mga lambda expression, ginagawang compact at concise ng mga reference na pamamaraan ang mga construct ng wika, na ginagawa itong batay sa template. Nasa ibaba ang isang klase Carbilang isang halimbawa ng iba't ibang kahulugan ng pamamaraan, i-highlight natin ang apat na sinusuportahang uri ng mga pamamaraan ng sanggunian:
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() );
    }
}
Ang unang paraan ng sanggunian ay isang sanggunian sa isang constructor na may syntax Class::newo isang alternatibo para sa generics Class< T >::new. Tandaan na ang tagabuo ay walang mga argumento.
final Car car = Car.create( Car::new );
final List<Car> cars = Arrays.asList( car );
Ang pangalawang opsyon ay isang sanggunian sa isang static na pamamaraan na may syntax Class::static_method. Tandaan na ang pamamaraan ay tumatagal ng eksaktong isang parameter ng uri Car.
cars.forEach( Car::collide );
Ang ikatlong uri ay isang sanggunian sa isang paraan ng isang halimbawa ng isang arbitrary na bagay ng isang tiyak na uri na may syntax Class::method. Tandaan na walang mga argumento ang tinatanggap ng pamamaraan.
cars.forEach( Car::repair );
At ang huli, pang-apat na uri ay isang sanggunian sa isang paraan ng isang halimbawa ng isang partikular na klase na may syntax instance::method. Pakitandaan na ang paraan ay tumatanggap lamang ng isang parameter ng uri Car.
final Car police = Car.create( Car::new );
cars.forEach( police::follow );
Ang pagpapatakbo ng lahat ng mga halimbawang ito bilang mga Java program ay gumagawa ng sumusunod na console output ( Carmaaaring mag-iba ang sanggunian ng klase):
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
Para sa mas detalyadong impormasyon at mga detalye ng mga pamamaraan ng sanggunian, mangyaring sumangguni sa opisyal na dokumentasyon .

2.4. Mga duplicate na anotasyon

Dahil ipinakilala ng Java 5 ang suporta para sa mga anotasyon , naging napakasikat at napakalawak na ginagamit ng feature na ito. Gayunpaman, ang isa sa mga limitasyon ng paggamit ng mga anotasyon ay ang katotohanan na ang parehong anotasyon ay hindi maaaring ideklara nang higit sa isang beses sa parehong lugar. Sinira ng Java 8 ang panuntunang ito at ipinakilala ang mga duplicate na anotasyon. Nagbibigay-daan ito sa parehong mga anotasyon na maulit nang maraming beses sa lokasyon kung saan idineklara ang mga ito. Ang mga duplicate na anotasyon ay dapat mag-annotate sa kanilang mga sarili gamit ang anotasyon @Repeatable. Sa katunayan, hindi ito gaanong pagbabago sa wika dahil ito ay isang trick ng compiler, habang ang pamamaraan ay nananatiling pareho. Tingnan natin ang isang simpleng halimbawa:
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() );
        }
    }
}
Tulad ng nakikita natin, ang klase Filteray may annotated na @Repeatable( Filters. class). Filtersay simpleng may-ari ng mga anotasyon Filter, ngunit sinusubukan ng Java compiler na itago ang kanilang presensya mula sa mga developer. Kaya, ang interface Filterableay naglalaman ng mga anotasyon Filterna idineklara nang dalawang beses (nang hindi binabanggit Filters). Nagbibigay din ang Reflection API ng bagong paraan getAnnotationsByType()para sa pagbabalik ng mga duplicate na anotasyon ng ilang uri (tandaan na ang Filterable. class.getAnnotation( Filters. class) ay magbabalik ng compiler-injected instance Filters). Ang output ng programa ay magiging ganito:
filter1
filter2
Para sa mas detalyadong impormasyon, mangyaring sumangguni sa opisyal na dokumentasyon .

2.5. Pinahusay na uri ng hinuha

Ang Java 8 compiler ay nakatanggap ng maraming uri ng pagpapabuti ng inference. Sa maraming mga kaso, ang mga tahasang uri ng mga parameter ay maaaring tukuyin ng compiler, sa gayon ginagawang mas malinis ang code. Tingnan natin ang isang halimbawa:
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;
    }
}
At narito ang paggamit sa uri 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() );
    }
}
Ang uri ng parameter Value.defaultValue()ay awtomatikong tinutukoy at hindi kailangang ibigay nang tahasan. Sa Java 7, ang parehong halimbawa ay hindi mag-compile at dapat na muling isulat bilang <NOBR>Value.<String>defaultValue()</NOBR>.

2.6. Pinalawak na suporta sa anotasyon

Pinapalawak ng Java 8 ang konteksto kung saan maaaring gamitin ang mga anotasyon. Sa ngayon, halos anumang bagay ay maaaring magkaroon ng anotasyon: mga lokal na variable, generic na uri, superclass at ipinatupad na mga interface, kahit na mga pagbubukod sa pamamaraan. Ang ilang mga halimbawa ay ipinakita sa ibaba:
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_USEat ElementType.TYPE_PARAMETERdalawang bagong uri ng elemento upang ilarawan ang nauugnay na konteksto ng anotasyon. Annotation Processing APIsumailalim din sa maliliit na pagbabago upang makilala ang mga bagong uri ng anotasyon sa Java.

3. Mga bagong feature sa Java compiler

3.1. Mga pangalan ng parameter

Sa buong panahon, ang mga developer ng Java ay nag-imbento ng iba't ibang paraan upang mag-imbak ng mga pangalan ng parameter ng pamamaraan sa Java bytecode upang gawing available ang mga ito sa runtime (halimbawa, ang Paranamer library ). Sa wakas, nilikha ng Java 8 ang mahirap na function na ito sa wika (gamit ang Reflection API at pamamaraan Parameter.getName()) at bytecode (gamit ang bagong argumento ng compiler 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() );
        }
    }
}
Kung kino-compile mo ang klase na ito nang hindi gumagamit ng argumento –parametersat pagkatapos ay patakbuhin ang programa, makakakita ka ng ganito:
Parameter: arg0
Sa parameter –parametersna ipinasa sa compiler, ang output ng programa ay magkakaiba (ang aktwal na pangalan ng parameter ay ipapakita):
Parameter: args
Para sa mga advanced na user ng Maven, ang –parameters argument ay maaaring idagdag sa compilation gamit ang seksyon 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>
Upang suriin ang pagkakaroon ng mga pangalan ng parameter mayroong isang maginhawang isNamePresent()paraan na ibinigay ng klase Parameter.

4. Bagong Java Tools

Ang Java 8 ay may kasamang bagong hanay ng mga tool sa command line. Sa seksyong ito ay titingnan natin ang pinakakawili-wili sa kanila.

4.1. Nashorn engine: jjs

Ang jjs ay isang standalone Nashorn engine na nakabatay sa command line. Kinakailangan ang isang listahan ng mga file ng source code ng JavaScript at pinapatakbo ang mga ito. Halimbawa, gumawa tayo ng func.js file na may sumusunod na nilalaman:
function f() {
     return 1;
};

print( f() + 1 );
Upang patakbuhin ang file na ito, ipasa natin ito bilang argumento sa jjs :
jjs func.js
Ang output ng console ay magiging ganito:
2
Para sa higit pang mga detalye tingnan ang dokumentasyon .

4.2. Class Dependency Analyzer: jdeps

Ang jdeps ay isang napakahusay na tool sa command line. Ipinapakita nito ang mga dependency sa antas ng pakete o klase para sa mga klase ng Java. Tumatanggap ito ng .class na file, folder o JAR file bilang input. Bilang default , ang jdeps ay naglalabas ng mga dependencies sa karaniwang output (console). Bilang halimbawa, tingnan natin ang ulat ng dependency ng sikat na library ng Spring Framework . Upang panatilihing maikli ang halimbawa, tingnan natin ang mga dependency para sa JAR file lamang org.springframework.core-3.0.5.RELEASE.jar.
jdeps org.springframework.core-3.0.5.RELEASE.jar
Ang utos na ito ay naglalabas ng marami, kaya susuriin lamang namin ang bahagi ng output. Ang mga dependency ay pinagsama ayon sa mga pakete. Kung walang mga dependency, hindi nahanap ay ipapakita .
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
Para sa mas detalyadong impormasyon, mangyaring sumangguni sa opisyal na dokumentasyon .
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION