JavaRush /Blog Java /Random-MS /Coffee break #155. 10 Fungsi Teratas dalam Java

Coffee break #155. 10 Fungsi Teratas dalam Java

Diterbitkan dalam kumpulan

10 Fungsi Teratas dalam Java

Sumber: DZone Artikel ini menyenaraikan sepuluh ciri pengaturcaraan Java yang sering digunakan oleh pembangun dalam kerja harian mereka. Coffee break #155.  10 fungsi teratas dalam Java - 1

1. Kaedah Kilang Kutipan

Koleksi adalah salah satu ciri yang paling biasa digunakan dalam pengaturcaraan. Ia digunakan sebagai bekas di mana kita menyimpan objek dan menyampaikannya. Koleksi juga digunakan untuk mengisih, mencari dan mengulang objek, menjadikan kehidupan pengaturcara lebih mudah. Mereka mempunyai beberapa antara muka asas seperti Senarai, Set, Peta, serta beberapa pelaksanaan. Cara tradisional untuk mencipta Koleksi dan Peta boleh kelihatan jelas kepada banyak pembangun. Itulah sebabnya Java 9 memperkenalkan beberapa kaedah kilang yang ringkas. Senarai :
List countries = List.of("Bangladesh", "Canada", "United States", "Tuvalu");
Set :
Set countries = Set.of("Bangladesh", "Canada", "United States", "Tuvalu");
Peta :
Map countriesByPopulation = Map.of("Bangladesh", 164_689_383,
                                                            "Canada", 37_742_154,
                                                            "United States", 331_002_651,
                                                            "Tuvalu", 11_792);
Kaedah kilang sangat berguna apabila kita ingin mencipta bekas yang tidak boleh diubah. Tetapi jika anda akan membuat koleksi boleh ubah, adalah disyorkan untuk menggunakan pendekatan tradisional.

2. Inferens Jenis Tempatan

Java 10 menambah inferens jenis untuk pembolehubah tempatan. Sebelum ini, pembangun perlu menentukan jenis dua kali apabila mengisytiharkan dan memulakan objek. Ia sangat memenatkan. Lihat contoh berikut:
Map> properties = new HashMap<>();
Jenis maklumat di kedua-dua belah pihak ditunjukkan di sini. Jika kita mentakrifkannya di satu tempat, maka pembaca kod dan pengkompil Java akan mudah memahami bahawa ia mestilah jenis Peta. Inferens jenis tempatan melakukan perkara itu. Berikut ialah contoh:
var properties = new HashMap>();
Kini semuanya ditulis sekali sahaja dan kod itu tidak kelihatan lebih teruk. Dan apabila kita memanggil kaedah dan menyimpan hasilnya dalam pembolehubah, kod itu menjadi lebih pendek. Contoh:
var properties = getProperties();
Dan selanjutnya:
var countries = Set.of("Bangladesh", "Canada", "United States", "Tuvalu");
Walaupun inferens jenis tempatan kelihatan seperti ciri yang mudah, sesetengah orang mengkritiknya. Sesetengah pembangun berpendapat bahawa ini mengurangkan kebolehbacaan. Dan ini lebih penting daripada ringkasan.

3. Ungkapan Suis Lanjutan

Pernyataan suis tradisional telah wujud di Jawa sejak awal dan mengingatkan C dan C++ ketika itu. Ini baik, tetapi apabila bahasa berkembang, pengendali ini tidak menawarkan kami apa-apa peningkatan sehingga Java 14. Sudah tentu, ia mempunyai beberapa kelemahan. Yang paling terkenal ialah fall -through: Untuk menyelesaikan masalah ini, pembangun menggunakan penyataan rehat, yang sebahagian besarnya merupakan kod boilerplate. Walau bagaimanapun, Java 14 memperkenalkan versi penyataan suis yang lebih baik dengan senarai fungsi yang lebih besar. Sekarang kita tidak perlu lagi menambah penyataan rehat dan ini menyelesaikan masalah kegagalan. Selain itu, pernyataan suis boleh mengembalikan nilai, yang bermaksud kita boleh menggunakannya sebagai ungkapan dan menetapkannya kepada pembolehubah.
int day = 5;
String result = switch (day) {
    case 1, 2, 3, 4, 5 -> "Weekday";
    case 6, 7 -> "Weekend";
    default -> "Unexpected value: " + day;
};

4. Rekod

Walaupun Rekod adalah ciri yang agak baharu yang diperkenalkan di Java 16, ramai pembangun mendapati ia sangat berguna, terutamanya disebabkan oleh penciptaan objek tidak boleh diubah. Selalunya kita memerlukan objek data dalam program kita untuk menyimpan atau menghantar nilai dari satu kaedah ke kaedah yang lain. Sebagai contoh, kelas untuk memindahkan koordinat x, y dan z, yang akan kami tulis seperti berikut:
package ca.bazlur.playground;

import java.util.Objects;

public final class Point {
    private final int x;
    private final int y;
    private final int z;

    public Point(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public int x() {
        return x;
    }

    public int y() {
        return y;
    }

    public int z() {
        return z;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) return true;
        if (obj == null || obj.getClass() != this.getClass()) return false;
        var that = (Point) obj;
        return this.x == that.x &&
                this.y == that.y &&
                this.z == that.z;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y, z);
    }

    @Override
    public String toString() {
        return "Point[" +
                "x=" + x + ", " +
                "y=" + y + ", " +
                "z=" + z + ']';
    }

}
Kelas kelihatan terlalu bertele-tele. Dengan bantuan entri, semua kod ini boleh digantikan dengan versi yang lebih ringkas:
package ca.bazlur.playground;

public record Point(int x, int y, int z) {
}

5. Pilihan

Kaedah ialah kontrak di mana kita menentukan syarat. Kami menentukan parameter dengan jenisnya, serta jenis pulangan. Kami kemudian menjangkakan bahawa apabila kaedah itu dipanggil, ia akan bertindak mengikut kontrak. Walau bagaimanapun, selalunya kita berakhir dengan null daripada kaedah dan bukannya nilai jenis yang ditentukan. Ini adalah kesilapan. Untuk menyelesaikan masalah ini, pemula biasanya menguji nilai dengan syarat if, tidak kira sama ada nilai itu batal atau tidak. Contoh:
public class Playground {

    public static void main(String[] args) {
        String name = findName();
        if (name != null) {
            System.out.println("Length of the name : " + name.length());
        }
    }

    public static String findName() {
        return null;
    }
}
Lihat kod di atas. Kaedah findName sepatutnya mengembalikan String , tetapi ia mengembalikan null. Inisiator kini mesti menyemak nol terlebih dahulu untuk menangani masalah itu. Jika pemula terlupa untuk melakukan ini, maka kita akan mendapat NullPointerException . Sebaliknya, jika tandatangan kaedah menunjukkan kemungkinan tidak dikembalikan, maka ini akan menyelesaikan semua kekeliruan. Dan di sinilah Pilihan boleh membantu kami .
import java.util.Optional;

public class Playground {

    public static void main(String[] args) {
        Optional optionalName = findName();
        optionalName.ifPresent(name -> {
            System.out.println("Length of the name : " + name.length());
        });
    }

    public static Optional findName() {
        return Optional.empty();
    }
}
Di sini kami telah menulis semula kaedah findName dengan pilihan Pilihan untuk tidak mengembalikan sebarang nilai. Ini memberi amaran kepada pengaturcara terlebih dahulu dan menyelesaikan masalah.

6. API Masa Tarikh Java

Setiap pembangun keliru pada satu tahap atau yang lain dengan mengira tarikh dan masa. Ini tidak keterlaluan. Ini disebabkan terutamanya oleh kekurangan API Java yang baik untuk bekerja dengan tarikh dan masa. Kini masalah ini tidak lagi relevan, kerana Java 8 memperkenalkan set API yang sangat baik dalam pakej java.time, yang menyelesaikan semua isu yang berkaitan dengan tarikh dan masa. Pakej java.time mempunyai banyak antara muka dan kelas yang menghapuskan kebanyakan masalah, termasuk zon waktu. Kelas yang paling biasa digunakan dalam pakej ini ialah:
  • LocalDate
  • LocalTime
  • LocalDateTime
  • Tempoh
  • Tempoh
  • ZonedDateTime
Contoh menggunakan kelas daripada pakej java.time:
import java.time.LocalDate;
import java.time.Month;

public class Playground3 {
    public static void main(String[] args) {
        LocalDate date = LocalDate.of(2022, Month.APRIL, 4);
        System.out.println("year = " + date.getYear());
        System.out.println("month = " + date.getMonth());
        System.out.println("DayOfMonth = " + date.getDayOfMonth());
        System.out.println("DayOfWeek = " + date.getDayOfWeek());
        System.out.println("isLeapYear = " + date.isLeapYear());
    }
}
Contoh menggunakan kelas LocalTime untuk mengira masa:
LocalTime time = LocalTime.of(20, 30);
int hour = time.getHour();
int minute = time.getMinute();
time = time.withSecond(6);
time = time.plusMinutes(3);
Menambah zon waktu:
ZoneId zone = ZoneId.of("Canada/Eastern");
LocalDate localDate = LocalDate.of(2022, Month.APRIL, 4);
ZonedDateTime zonedDateTime = date.atStartOfDay(zone);

7.NullPointerException

Setiap pembangun membenci NullPointerException. Ia boleh menjadi sangat sukar apabila StackTrace tidak memberikan maklumat berguna tentang apa sebenarnya masalahnya. Untuk menunjukkan ini, mari kita lihat kod sampel:
package com.bazlur;

public class Main {

    public static void main(String[] args) {
        User user = null;
        getLengthOfUsersName(user);
    }

    public static void getLengthOfUsersName(User user) {
        System.out.println("Length of first name: " + user.getName().getFirstName());
    }
}

class User {
    private Name name;
    private String email;

    public User(Name name, String email) {
        this.name = name;
        this.email = email;
    }

   //getter
   //setter
}

class Name {
    private String firstName;
    private String lastName;

    public Name(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

   //getter
   //setter
}
Lihat kaedah asas dalam petikan ini. Kami melihat bahawa NullPointerException akan dilemparkan seterusnya . Jika kami menjalankan dan menyusun kod dalam versi sebelum Java 14, kami akan mendapat StackTrace berikut:
Exception in thread "main" java.lang.NullPointerException
at com.bazlur.Main.getLengthOfUsersName(Main.java:11)
at com.bazlur.Main.main(Main.java:7)
Terdapat sedikit maklumat di sini tentang tempat dan sebab NullPointerException berlaku . Tetapi dalam Java 14 dan versi yang lebih baru, kami mendapat lebih banyak maklumat dalam StackTrace, yang sangat mudah. Di Java 14 kita akan melihat:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "ca.bazlur.playground.User.getName()" because "user" is null
at ca.bazlur.playground.Main.getLengthOfUsersName(Main.java:12)
at ca.bazlur.playground.Main.main(Main.java:8)

8. CompletableFuture

Kami menulis program baris demi baris, dan ia biasanya dilaksanakan baris demi baris. Tetapi ada kalanya kita memerlukan pelaksanaan selari untuk menjadikan program lebih cepat. Untuk ini kami biasanya menggunakan Java Thread. Pengaturcaraan benang Java tidak selalu mengenai pengaturcaraan selari. Sebaliknya, ia memberi kita keupayaan untuk mengarang beberapa modul program bebas yang akan dilaksanakan secara bebas dan selalunya secara tidak segerak. Walau bagaimanapun, pengaturcaraan benang agak sukar, terutamanya untuk pemula. Inilah sebabnya mengapa Java 8 menawarkan API yang lebih mudah yang membolehkan anda melaksanakan sebahagian daripada program secara tidak segerak. Mari lihat contoh. Katakan kita perlu memanggil tiga API REST dan kemudian menggabungkan hasilnya. Kita boleh panggil mereka satu persatu. Jika setiap satu daripada mereka mengambil masa kira-kira 200 milisaat, maka jumlah masa untuk menerimanya akan mengambil masa 600 milisaat. Bagaimana jika kita boleh menjalankannya secara selari? Oleh kerana pemproses moden biasanya berbilang teras, mereka boleh mengendalikan tiga panggilan rehat pada tiga pemproses berbeza dengan mudah. Menggunakan CompletableFuture kita boleh melakukannya dengan mudah.
package ca.bazlur.playground;

import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class SocialMediaService {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        var service = new SocialMediaService();

        var start = Instant.now();
        var posts = service.fetchAllPost().get();
        var duration = Duration.between(start, Instant.now());

        System.out.println("Total time taken: " + duration.toMillis());
    }

    public CompletableFuture> fetchAllPost() {
        var facebook = CompletableFuture.supplyAsync(this::fetchPostFromFacebook);
        var linkedIn = CompletableFuture.supplyAsync(this::fetchPostFromLinkedIn);
        var twitter = CompletableFuture.supplyAsync(this::fetchPostFromTwitter);

        var futures = List.of(facebook, linkedIn, twitter);

        return CompletableFuture.allOf(futures.toArray(futures.toArray(new CompletableFuture[0])))
                .thenApply(future -> futures.stream()
                        .map(CompletableFuture::join)
                        .toList());
    }
    private String fetchPostFromTwitter() {
        sleep(200);
        return "Twitter";
    }

    private String fetchPostFromLinkedIn() {
        sleep(200);
        return "LinkedIn";
    }

    private String fetchPostFromFacebook() {
        sleep(200);
        return "Facebook";
    }

    private void sleep(int millis) {
        try {
            TimeUnit.MILLISECONDS.sleep(millis);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

9. Ungkapan Lambda

Ungkapan Lambda mungkin merupakan ciri yang paling berkuasa dalam bahasa Java. Mereka mengubah cara kami menulis kod. Ungkapan lambda adalah seperti fungsi tanpa nama yang boleh mengambil hujah dan mengembalikan nilai. Kita boleh menetapkan fungsi kepada pembolehubah dan menyampaikannya sebagai argumen kepada kaedah, dan kaedah itu boleh mengembalikannya. Dia mempunyai badan. Satu-satunya perbezaan dari kaedah ialah tiada nama. Ungkapan adalah pendek dan padat. Mereka biasanya tidak mengandungi banyak kod boilerplate. Mari lihat contoh di mana kita perlu menyenaraikan semua fail dalam direktori dengan sambungan .java.
var directory = new File("./src/main/java/ca/bazlur/playground");
String[] list = directory.list(new FilenameFilter() {
    @Override
    public boolean accept(File dir, String name) {
        return name.endsWith(".java");
    }
});
Jika anda melihat dengan teliti sekeping kod ini, kami telah menyerahkan senarai kelas dalaman tanpa nama () kepada kaedah . Dan dalam kelas dalaman kami meletakkan logik untuk menapis fail. Pada asasnya, kami berminat dengan bahagian logik ini, bukan corak di sekeliling logik. Ungkapan lambda membolehkan kami mengalih keluar keseluruhan templat dan kami boleh menulis kod yang menarik minat kami. Berikut ialah contoh:
var directory = new File("./src/main/java/ca/bazlur/playground");
String[] list = directory.list((dir, name) -> name.endsWith(".java"));
Sudah tentu, ini hanyalah satu contoh; ungkapan lambda mempunyai banyak faedah lain.

10. API Strim

Dalam kerja harian kami, salah satu tugas biasa ialah memproses set data. Ia mempunyai beberapa operasi biasa seperti menapis, mengubah dan mengumpul hasil. Sebelum Java 8, operasi sedemikian adalah bersifat penting. Kami terpaksa menulis kod untuk niat kami (iaitu, perkara yang kami mahu capai) dan cara kami ingin melakukannya. Dengan ciptaan ungkapan lambda dan API Strim, kami kini boleh menulis fungsi pemprosesan data secara deklaratif. Kami hanya menunjukkan niat kami, dan kami tidak perlu menulis bagaimana kami mendapat hasilnya. Berikut ialah contoh: Kami mempunyai senarai buku dan kami ingin mencari semua nama buku Java, dipisahkan dengan koma dan diisih.
public static String getJavaBooks(List books) {
    return books.stream()
            .filter(book -> Objects.equals(book.language(), "Java"))
            .sorted(Comparator.comparing(Book::price))
            .map(Book::name)
            .collect(Collectors.joining(", "));
}
Kod di atas adalah mudah, boleh dibaca dan ringkas. Tetapi di bawah anda boleh melihat kod imperatif alternatif:
public static String getJavaBooksImperatively(List books) {
    var filteredBook = new ArrayList();
    for (Book book : books) {
        if (Objects.equals(book.language(), "Java")){
            filteredBook.add(book);
        }
    }
    filteredBook.sort(new Comparator() {
        @Override
        public int compare(Book o1, Book o2) {
            return Integer.compare(o1.price(), o2.price());
        }
    });

    var joiner = new StringJoiner(",");
    for (Book book : filteredBook) {
        joiner.add(book.name());
    }

    return joiner.toString();
}
Walaupun kedua-dua kaedah mengembalikan nilai yang sama, kita dapat melihat dengan jelas perbezaannya.
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION