JavaRush /Java Blog /Random-ID /Rehat kopi #155. 10 Fungsi Teratas di Java

Rehat kopi #155. 10 Fungsi Teratas di Java

Dipublikasikan di grup Random-ID

10 Fungsi Teratas di Java

Sumber: DZone Artikel ini mencantumkan sepuluh fitur pemrograman Java yang sering digunakan oleh developer dalam pekerjaan sehari-hari. Rehat kopi #155.  10 fungsi teratas di Java - 1

1. Metode Pabrik Pengumpulan

Koleksi adalah salah satu fitur yang paling umum digunakan dalam pemrograman. Mereka digunakan sebagai wadah tempat kita menyimpan benda dan menyebarkannya. Koleksi juga digunakan untuk mengurutkan, mencari, dan mengulang objek, membuat hidup seorang programmer menjadi lebih mudah. Mereka memiliki beberapa antarmuka dasar seperti Daftar, Set, Peta, serta beberapa implementasi. Cara tradisional dalam membuat Koleksi dan Peta mungkin tampak bertele-tele bagi banyak pengembang. Itu sebabnya Java 9 memperkenalkan beberapa metode pabrik yang ringkas. Daftar :
List countries = List.of("Bangladesh", "Canada", "United States", "Tuvalu");
Mengatur :
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);
Metode pabrik sangat berguna ketika kita ingin membuat wadah yang tidak dapat diubah. Namun jika Anda ingin membuat koleksi yang bisa diubah, disarankan untuk menggunakan pendekatan tradisional.

2. Inferensi Tipe Lokal

Java 10 menambahkan inferensi tipe untuk variabel lokal. Sebelumnya, pengembang harus menentukan tipe dua kali saat mendeklarasikan dan menginisialisasi suatu objek. Itu sangat melelahkan. Lihatlah contoh berikut:
Map> properties = new HashMap<>();
Jenis informasi di kedua sisi ditunjukkan di sini. Jika kita mendefinisikannya di satu tempat, maka pembaca kode dan compiler Java akan dengan mudah memahami bahwa itu harus bertipe Map. Inferensi tipe lokal melakukan hal itu. Berikut ini contohnya:
var properties = new HashMap>();
Sekarang semuanya ditulis hanya sekali dan kodenya tidak terlihat lebih buruk. Dan ketika kita memanggil suatu metode dan menyimpan hasilnya dalam sebuah variabel, kodenya menjadi lebih pendek. Contoh:
var properties = getProperties();
Dan selanjutnya:
var countries = Set.of("Bangladesh", "Canada", "United States", "Tuvalu");
Meskipun inferensi tipe lokal tampak seperti fitur yang mudah digunakan, beberapa orang mengkritiknya. Beberapa pengembang berpendapat bahwa hal ini mengurangi keterbacaan. Dan ini lebih penting daripada singkatnya.

3. Ekspresi Pengalihan Tingkat Lanjut

Pernyataan switch tradisional telah ada di Java sejak awal dan mengingatkan pada C dan C++ saat itu. Ini baik-baik saja, tetapi seiring berkembangnya bahasa, operator ini tidak menawarkan perbaikan apa pun kepada kami hingga Java 14. Tentu saja, operator ini memiliki beberapa kelemahan. Yang paling terkenal adalah kegagalan : Untuk mengatasi masalah ini, pengembang menggunakan pernyataan break, yang sebagian besar merupakan kode boilerplate. Namun, Java 14 memperkenalkan versi pernyataan switch yang lebih baik dengan daftar fungsi yang jauh lebih besar. Sekarang kita tidak perlu lagi menambahkan pernyataan break dan ini menyelesaikan masalah kegagalan. Selain itu, pernyataan switch dapat mengembalikan nilai, yang berarti kita dapat menggunakannya sebagai ekspresi dan menetapkannya ke variabel.
int day = 5;
String result = switch (day) {
    case 1, 2, 3, 4, 5 -> "Weekday";
    case 6, 7 -> "Weekend";
    default -> "Unexpected value: " + day;
};

4. Catatan

Meskipun Records adalah fitur yang relatif baru yang diperkenalkan di Java 16, banyak pengembang menganggapnya sangat berguna, terutama karena pembuatan objek yang tidak dapat diubah. Seringkali kita membutuhkan objek data dalam program kita untuk menyimpan atau meneruskan nilai dari satu metode ke metode lainnya. Misalnya kelas untuk mentransfer koordinat x, y dan z, yang akan kita tulis sebagai 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 tampaknya terlalu bertele-tele. Dengan bantuan entri, seluruh kode ini dapat diganti dengan versi yang lebih ringkas:
package ca.bazlur.playground;

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

5. Opsional

Metode adalah kontrak di mana kita mendefinisikan kondisi. Kami menentukan parameter dengan tipenya, serta tipe pengembaliannya. Kami kemudian berharap bahwa ketika metode ini dipanggil, ia akan berperilaku sesuai dengan kontrak. Namun, sering kali kita mendapatkan null dari suatu metode alih-alih nilai dari tipe yang ditentukan. Ini adalah kesalahan. Untuk mengatasi hal ini, pemrakarsa biasanya menguji nilai dengan kondisi if, terlepas dari apakah nilainya null 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;
    }
}
Lihatlah kode di atas. Metode findName seharusnya mengembalikan String , tetapi mengembalikan null. Pemrakarsa sekarang harus memeriksa null terlebih dahulu untuk mengatasi masalah tersebut. Jika pemrakarsa lupa melakukan ini, maka kita akan mendapatkan NullPointerException . Di sisi lain, jika tanda tangan metode menunjukkan kemungkinan tidak dapat dikembalikan, maka ini akan menyelesaikan semua kebingungan. Dan di sinilah Opsional dapat membantu kita .
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 ulang metode findName dengan opsi Opsional untuk tidak mengembalikan nilai apa pun. Ini memperingatkan pemrogram terlebih dahulu dan memperbaiki masalah.

6. API Tanggal Waktu Java

Setiap pengembang sampai taraf tertentu bingung dengan penghitungan tanggal dan waktu. Hal ini tidak berlebihan. Hal ini terutama disebabkan oleh kurangnya Java API yang baik untuk bekerja dengan tanggal dan waktu. Sekarang masalah ini tidak lagi relevan, karena Java 8 memperkenalkan seperangkat API yang sangat baik dalam paket java.time, yang menyelesaikan semua masalah terkait tanggal dan waktu. Paket java.time memiliki banyak antarmuka dan kelas yang menghilangkan sebagian besar masalah, termasuk zona waktu. Kelas yang paling umum digunakan dalam paket ini adalah:
  • Tanggal Lokal
  • Waktu lokal
  • TanggalWaktu Lokal
  • Durasi
  • Periode
  • TanggalZonaWaktu
Contoh penggunaan kelas dari paket 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 penggunaan kelas LocalTime untuk menghitung waktu:
LocalTime time = LocalTime.of(20, 30);
int hour = time.getHour();
int minute = time.getMinute();
time = time.withSecond(6);
time = time.plusMinutes(3);
Menambahkan zona waktu:
ZoneId zone = ZoneId.of("Canada/Eastern");
LocalDate localDate = LocalDate.of(2022, Month.APRIL, 4);
ZonedDateTime zonedDateTime = date.atStartOfDay(zone);

7.NullPointerException

Setiap pengembang membenci NullPointerException. Hal ini bisa menjadi sangat sulit ketika StackTrace tidak memberikan informasi berguna tentang apa sebenarnya masalahnya. Untuk mendemonstrasikannya, mari kita lihat kode contoh:
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
}
Lihatlah metode dasar dalam bagian ini. Kami melihat bahwa NullPointerException akan dilempar berikutnya . Jika kita menjalankan dan mengkompilasi kode dalam versi sebelum Java 14, kita akan mendapatkan 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)
Ada sangat sedikit informasi di sini tentang di mana dan mengapa NullPointerException terjadi . Namun di Java 14 dan versi yang lebih baru, kami mendapatkan lebih banyak informasi di StackTrace, yang sangat memudahkan. 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. Masa Depan yang Dapat Diselesaikan

Kami menulis program baris demi baris, dan biasanya dijalankan baris demi baris. Namun ada kalanya kita membutuhkan eksekusi paralel untuk membuat program lebih cepat. Untuk ini kami biasanya menggunakan Java Thread. Pemrograman thread Java tidak selalu tentang pemrograman paralel. Sebaliknya, ini memberi kita kemampuan untuk menyusun beberapa modul program independen yang akan dijalankan secara independen dan seringkali bahkan secara asinkron. Namun pemrograman thread cukup sulit, terutama bagi pemula. Inilah sebabnya Java 8 menawarkan API sederhana yang memungkinkan Anda menjalankan sebagian program secara asinkron. Mari kita lihat sebuah contoh. Katakanlah kita perlu memanggil tiga REST API dan kemudian menggabungkan hasilnya. Kita bisa memanggil mereka satu per satu. Jika masing-masing membutuhkan waktu sekitar 200 milidetik, maka total waktu untuk menerimanya akan memakan waktu 600 milidetik. Bagaimana jika kita bisa menjalankannya secara paralel? Karena prosesor modern biasanya multi-core, mereka dapat dengan mudah menangani tiga panggilan istirahat pada tiga prosesor berbeda. Dengan menggunakan CompletableFuture kita dapat 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. Ekspresi Lambda

Ekspresi Lambda mungkin merupakan fitur paling kuat dari bahasa Java. Mereka mengubah cara kita menulis kode. Ekspresi lambda seperti fungsi anonim yang dapat mengambil argumen dan mengembalikan nilai. Kita dapat menetapkan suatu fungsi ke suatu variabel dan meneruskannya sebagai argumen ke suatu metode, dan metode tersebut dapat mengembalikannya. Dia memiliki tubuh. Satu-satunya perbedaan dari metode ini adalah tidak ada nama. Ekspresinya singkat dan padat. Biasanya tidak berisi banyak kode boilerplate. Mari kita lihat contoh di mana kita perlu membuat daftar semua file dalam direktori dengan ekstensi .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 mencermati potongan kode ini, kami telah meneruskan kelas dalam anonim list() ke metode . Dan di kelas dalam kami menempatkan logika untuk memfilter file. Intinya, kami tertarik pada bagian logika ini, bukan pola di sekitar logika tersebut. Ekspresi lambda memungkinkan kita menghapus seluruh template dan kita dapat menulis kode yang kita minati. Berikut ini contohnya:
var directory = new File("./src/main/java/ca/bazlur/playground");
String[] list = directory.list((dir, name) -> name.endsWith(".java"));
Tentu saja, ini hanyalah satu contoh; ekspresi lambda memiliki banyak manfaat lainnya.

10. Aliran API

Dalam pekerjaan kita sehari-hari, salah satu tugas umum adalah memproses kumpulan data. Ini memiliki beberapa operasi umum seperti memfilter, mengubah, dan mengumpulkan hasil. Sebelum Java 8, operasi semacam itu bersifat penting. Kami harus menulis kode untuk tujuan kami (yaitu, apa yang ingin kami capai) dan bagaimana kami ingin melakukannya. Dengan penemuan ekspresi lambda dan Stream API, kini kita dapat menulis fungsi pemrosesan data secara deklaratif. Kami hanya menunjukkan niat kami, dan kami tidak perlu menuliskan bagaimana kami mendapatkan hasilnya. Berikut contohnya: Kami memiliki daftar buku dan kami ingin mencari semua nama buku Java, dipisahkan dengan koma dan diurutkan.
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(", "));
}
Kode di atas sederhana, mudah dibaca dan ringkas. Namun di bawah ini Anda dapat melihat kode 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();
}
Meskipun kedua metode mengembalikan nilai yang sama, kita dapat melihat perbedaannya dengan jelas.
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION