JavaRush /Blog Jawa /Random-JV /Fitur Java 8 – Pandhuan Ultimate (Bagian 2)
0xFF
tingkat
Донецк

Fitur Java 8 – Pandhuan Ultimate (Bagian 2)

Diterbitake ing grup
Bagian kapindho terjemahan artikel Java 8 Features – The ULTIMATE Guide . Bagian pisanan ana ing kene (link bisa diganti). Fitur Java 8 – The Ultimate Guide (Part 2) - 1

5. Fitur anyar ing Jawa 8 perpustakaan

Java 8 wis nambahake akeh kelas anyar lan nambah kelas sing wis ana kanggo ndhukung konkurensi modern, program fungsional, tanggal / wektu, lan liya-liyane.

5.1. Kelas Opsional

NullPointerException sing misuwur minangka panyebab kegagalan aplikasi Java sing paling umum. Ing wektu sing suwe, proyek Google Guava sing apik banget ditampilake Optionalminangka solusi NullPointerException, saéngga nyegah kode supaya ora dicemari dening pamriksan null, lan minangka asil nyengkuyung nulis kode sing luwih resik. Kelas Jambu sing diilhami Google Optionalsaiki dadi bagéan saka Jawa 8. OptionalIku mung wadhah: bisa ngemot nilai utawa sawetara jinis Т, utawa mung null. Nyedhiyakake akeh cara sing migunani supaya pamriksan null sing jelas ora bisa ditrapake maneh. Deleng dokumentasi resmi kanggo informasi sing luwih rinci. Ayo goleki rong conto panggunaan cilik Optional: nganggo lan tanpa null.
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!" ) );
Cara kasebut isPresent()ngasilake bener yen conto kasebut Optionalngemot nilai non-null lan palsu . Cara kasebut orElseGet()ngemot mekanisme mundur kanggo asil yen Optionalngemot null, nrima fungsi kanggo ngasilake nilai standar. Cara map () ngowahi nilai saiki Optionallan ngasilake conto anyar Optional. Cara iki orElse()padha karo orElseGet(), nanging tinimbang fungsi njupuk nilai standar. Mangkene output saka program iki:
Full Name is set? false
Full Name: [none]
Hey Stranger!
Ayo goleki conto liyane:
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();
Asil bakal kaya iki:
First Name is set? true
First Name: Tom
Hey Tom!
Kanggo informasi sing luwih rinci, waca dokumentasi resmi .

5.2. Aliran

Stream API ( ) sing mentas ditambahake java.util.streamngenalake pemrograman gaya fungsional nyata ing Jawa. Iki minangka tambahan paling lengkap kanggo perpustakaan Jawa lan ngidini pangembang Jawa dadi luwih efisien lan uga bisa nggawe kode sing efisien, resik lan ringkes. Stream API nggawe pangolahan koleksi luwih gampang (nanging ora diwatesi, kaya sing bakal kita deleng mengko). Ayo njupuk kelas prasaja minangka conto 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 );
        }
    }
}
Tugas duwe sawetara raos (utawa pseudo-angel) lan bisa uga OPEN utawa CLOSE . Ayo dadi introduce koleksi cilik saka masalah kanggo muter karo.
final Collection<Task> tasks = Arrays.asList(
    new Task( Status.OPEN, 5 ),
    new Task( Status.OPEN, 13 ),
    new Task( Status.CLOSED, 8 )
);
Pitakonan pisanan sing arep digoleki yaiku pira poin sing saiki ana ing tugas OPEN ? Sadurunge Java 8, solusi sing biasa kanggo iki yaiku nggunakake iterator foreach. Nanging ing Jawa 8, jawabane yaiku stream: urutan unsur sing ndhukung operasi agregat sekuensial lan paralel.
// Подсчет общего количества очков всех активных задач с использованием sum()
final long totalPointsOfOpenTasks = tasks
    .stream()
    .filter( task -> task.getStatus() == Status.OPEN )
    .mapToInt( Task::getPoints )
    .sum();

System.out.println( "Total points: " + totalPointsOfOpenTasks );
Lan output console bakal katon kaya:
Total points: 18
Ayo ndeleng apa sing kedadeyan ing kene. Kaping pisanan, koleksi tugas diowahi dadi perwakilan streaming. Operasi banjur filternyaring kabeh tugas kanthi status TUTUP . Ing langkah sabanjure, operasi mapToIntngowahi stream Tasks menyang stream Integernggunakake cara Task::getPointskanggo saben Kayata Task. Pungkasan, kabeh poin disimpulake kanthi nggunakake metode sum, sing menehi asil pungkasan. Sadurunge pindhah menyang conto sabanjure, ana sawetara cathetan babagan benang sing kudu dielingi (rincian liyane ing kene ). Operasi streamdipérang dadi operasi penengah lan pungkasan . Operasi penengah ngasilake aliran anyar. Dheweke tansah kesed; nalika nindakake operasi penengah kayata filter, dheweke ora nindakake nyaring, nanging nggawe stream anyar, sing, yen wis rampung, ngemot unsur-unsur aliran asli sing cocog karo predikat sing diwenehake. Operasi winates , kayata forEachlan sum, bisa dilewati liwat stream kanggo ngasilake asil utawa efek samping. Sawise operasi pungkasan rampung, stream kasebut dianggep digunakake lan ora bisa digunakake maneh. Ing meh kabeh kasus, operasi pungkasan cenderung ngrampungake traversal liwat sumber data dhasar. Fitur penting liyane saka benang yaiku dhukungan kanggo proses paralel saka kothak. Ayo goleki conto iki, sing nemokake jumlah skor kabeh masalah.
// 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 );
Iki meh padha karo conto pisanan, kajaba kita nyoba ngolah kabeh tugas kanthi podo karo lan ngetung asil pungkasan nggunakake metode kasebut reduce. Mangkene output konsol:
Total points (all tasks): 26.0
Asring ana perlu kanggo klompok unsur miturut kritéria tartamtu. Conto nuduhake carane thread bisa mbantu iki.
// Группировка задач по их статусу
final Map<Status, List<Task>> map = tasks
    .stream()
    .collect( Collectors.groupingBy( Task::getStatus ) );
System.out.println( map );
Output konsol bakal kaya ing ngisor iki:
{CLOSED=[[CLOSED, 8]], OPEN=[[OPEN, 5], [OPEN, 13]]}
Kanggo ngrampungake conto masalah, ayo ngetung persentase sakabèhé (utawa bobot) saben masalah ing koleksi adhedhasar total poin:
// Подсчет веса каждой задачи (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 );
Output konsol bakal kaya iki:
[19%, 50%, 30%]
Pungkasan, kaya sing wis dingerteni sadurunge, Stream API ora mung kanggo koleksi Java. Operasi I / O sing khas, kayata maca file teks baris demi baris, minangka calon sing apik banget kanggo nggunakake pangolahan stream. Punika conto cilik kanggo mbuktekaken iki.
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 );
}
Cara kasebut onConsole, sing diarani benang, ngasilake benang sing padha karo panangan pribadi tambahan. Pawang pribadi diarani nalika metode close()diarani ing benang. Stream API bebarengan karo lambdas lan cara referensi bebarengan karo standar lan cara statis ing Jawa 8 minangka jawaban kanggo paradigma pangembangan piranti lunak modern. Kanggo informasi sing luwih rinci, waca dokumentasi resmi .

5.3. API Tanggal/Wektu (JSR 310)

Java 8 nggawa tampilan anyar kanggo manajemen tanggal lan wektu kanthi nyedhiyakake API Tanggal lan Wektu anyar (JSR 310) . Manipulasi tanggal lan wektu minangka salah sawijining titik nyeri paling awon kanggo pangembang Jawa. java.util.DateIng ngisor iki standar java.util.Calendarora umume nambah kahanan (bisa uga luwih mbingungake). Mangkono uga Joda-Time lair : alternatif API tanggal/wektu sing apik kanggo Java . Tanggal / Wektu API anyar ing Jawa 8 (JSR 310) dipengaruhi banget dening Joda-Time lan njupuk sing paling apik saka iku. Paket anyar java.timengemot kabeh kelas kanggo tanggal, wektu, tanggal / wektu, zona wektu, durasi, lan manipulasi wektu . Desain API njupuk immutability banget serius: owah-owahan ora diijini (pawulangan hard sinau saka java.util.Calendar). Yen modifikasi dibutuhake, conto anyar saka kelas sing cocog bakal bali. Ayo goleki kelas utama lan conto panggunaane. Kelas kapisan Clock, sing nyedhiyakake akses menyang saiki, tanggal lan wektu kanthi nggunakake zona wektu. Clockbisa digunakake tinimbang System.currentTimeMillis()lan TimeZone.getDefault().
// Получить системное время How смещение UTC
final Clock clock = Clock.systemUTC();
System.out.println( clock.instant() );
System.out.println( clock.millis() );
Conto output konsol:
2014-04-12T15:19:29.282Z
1397315969360
Kelas anyar liyane sing bakal kita deleng yaiku LocaleDatelan LocalTime. LocaleDatemung ngemot bagean tanggal tanpa zona wektu ing sistem tanggalan ISO-8601. Dadi, LocalTimemung ngemot bagean saka kode wektu>.
// получить местную 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 );
Conto output konsol:
2014-04-12
2014-04-12
11:25:54.568
15:25:54.568
LocalDateTimeconcatenates LocaleDatelan LocalTimelan ngemot tanggal lan wektu, nanging ora zona wektu, ing sistem tanggalan ISO-8601. Conto prasaja diwenehi ing ngisor iki.
// Get the local date/time
final LocalDateTime datetime = LocalDateTime.now();
final LocalDateTime datetimeFromClock = LocalDateTime.now( clock );

System.out.println( datetime );
System.out.println( datetimeFromClock );
Conto output konsol:
2014-04-12T11:37:52.309
2014-04-12T15:37:52.309
Yen sampeyan butuh tanggal / wektu kanggo zona wektu tartamtu, ZonedDateTime. Isine tanggal lan wektu ing sistem tanggalan ISO-8601. Ing ngisor iki sawetara conto kanggo zona wektu sing beda.
// Получение даты/времени для временной зоны
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 );
Conto output konsol:
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]
Lan pungkasane, ayo deleng kelas Duration: rentang wektu sajrone detik lan nanodetik. Iki ndadekake pitungan antarane rong tanggal banget prasaja. Ayo ndeleng carane nindakake iki:
// Получаем разницу между двумя датами
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() );
Conto ing ndhuwur ngitung durasi (ing dina lan jam) antarane rong tanggal, 16 April 2014 lan 16 April 2015 . Punika conto output console:
Duration in days: 365
Duration in hours: 8783
Kesan sakabèhé saka tanggal / wektu anyar ing Jawa 8 banget, banget positif. Sebagéyan amarga owah-owahan kasebut adhedhasar dhasar sing diuji perang (Joda-Time), sebagian amarga wektu iki masalah kasebut dipikirake maneh lan swara para pangembang dirungokake. Kanggo rincian, waca dokumentasi resmi .

5.4. Nashorn JavaScript engine

Java 8 dilengkapi mesin JavaScript Nashorn anyar , sing ngidini sampeyan ngembangake lan mbukak jinis aplikasi JavaScript tartamtu ing JVM. Mesin JavaScript Nashorn minangka implementasine liyane saka javax.script.ScriptEngine sing ngetutake aturan sing padha supaya Java lan JavaScript bisa sesambungan. Punika conto cilik.
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;" ) );
Conto output konsol:
jdk.nashorn.api.scripting.NashornScriptEngine
Result: 2

5.5. dhasar64

Pungkasan, dhukungan kanggo enkoding Base64 ditemokake ing perpustakaan standar Jawa kanthi rilis Java 8. Gampang banget digunakake, contone nduduhake iki.
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 );
    }
}
Output konsol program nuduhake teks sing dienkode lan didekode:
QmFzZTY0IGZpbmFsbHkgaW4gSmF2YSA4IQ==
Base64 finally in Java 8!
Ana uga kelas kanggo ngodhe/dekoder sing ramah-URL, uga encoder/dekoder sing ramah-MIMI ( Base64.getUrlEncoder()/ Base64.getUrlDecoder(), Base64.getMimeEncoder()/ Base64.getMimeDecoder()).

5.6. Parallel Arrays

Rilis Java 8 nambahake akeh cara anyar kanggo pangolahan array paralel. Mbok sing paling penting iki parallelSort(), kang bisa nemen nyepetake ngurutake ing mesin multi-inti. Conto cilik ing ngisor iki nuduhake kulawarga metode anyar ( parallelXxx) ing tumindak.
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();
    }
}
Potongan kode cilik iki nggunakake cara parallelSetAll()kanggo ngisi array kanthi 20.000 nilai acak. Sawise iki ditrapake parallelSort(). Program kasebut nyithak 10 unsur pisanan sadurunge lan sawise ngurutake kanggo nuduhake yen array kasebut bener-bener diurutake. Output program conto bisa katon kaya iki (Elinga yen unsur-unsur array kasebut acak).
Unsorted: 591217 891976 443951 424479 766825 351964 242997 642839 119108 552378
Sorted: 39 220 263 268 325 607 655 678 723 793

5.7. Paralelisme

Cara anyar wis ditambahake ing kelas java.util.concurrent.ConcurrentHashMapkanggo ndhukung operasi agregat adhedhasar obyek stream sing mentas ditambahake lan ekspresi lambda. Uga cara anyar wis ditambahake ing kelas java.util.concurrent.ForkJoinPoolkanggo ndhukung pooling sing dienggo bareng (ndeleng uga kursus gratis babagan konkurensi Jawa ). A kelas anyar java.util.concurrent.locks.StampedLockwis ditambahaké kanggo nyedhiyani ngunci basis kemampuan karo telung mode akses kanggo diwaca / nulis kontrol (bisa dianggep minangka alternatif sing luwih apik kanggo sing ora dadi apik java.util.concurrent.locks.ReadWriteLock). Kelas anyar sing wis ditambahake menyang paket java.util.concurrent.atomic:
  • DoubleAccumulator
  • DoubleAdder
  • LongAccumulator
  • LongAdder

6. Fitur anyar ing lingkungan runtime Java (JVM)

Wilayah kasebut PermGenwis pensiun lan diganti dening Metaspace (JEP 122). opsi JVM -XX:PermSizelan -XX:MaxPermSizewis diganti dening -XX:MetaSpaceSizelan -XX:MaxMetaspaceSizemungguh.

7. Kesimpulan

Masa depan ana ing kene: Java 8 wis mindhah platform kasebut maju kanthi menehi fitur sing ngidini pangembang dadi luwih produktif. Isih banget awal kanggo mindhah sistem produksi menyang Java 8, nanging adopsi kudu alon-alon wiwit tuwuh sajrone sawetara wulan sabanjure. Nanging, saiki iki wektu kanggo miwiti nyiapake basis kode kanggo kompatibilitas Java 8 lan siyap nggabungake owah-owahan Java 8 yen wis aman lan cukup stabil. Minangka bukti nrima masyarakat Jawa 8, Pivotal bubar ngrilis Spring Framework kanthi dhukungan produksi kanggo Java 8 . Sampeyan bisa menehi masukan babagan fitur anyar sing nyenengake ing Jawa 8 ing komentar.

8. Sumber

Sawetara sumber daya tambahan sing mbahas macem-macem aspek fitur Java 8 kanthi jero:
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION