JavaRush /Blog Java /Random-VI /Loại bỏ các vòng lặp trong Java 8
KapChook
Mức độ
Volga

Loại bỏ các vòng lặp trong Java 8

Xuất bản trong nhóm
Phong cách chức năng được giới thiệu trong Java 8 là một sự bổ sung tuyệt vời cho ngôn ngữ này. Bây giờ Java không phải là OOP thuần túy, bây giờ nó là sự kết hợp giữa OOP và lập trình hàm. Đây là yếu tố thay đổi cuộc chơi và chúng ta cần thay đổi bộ não OOP của mình để tiếp thu những thay đổi này. Loại bỏ vòng lặp trong Java 8 - 1Nhưng tại sao chúng ta phải chấp nhận những thay đổi này? Tại sao chúng ta phải lãng phí thời gian để cố gắng làm quen với phong cách chức năng khi chúng ta có thể giải quyết vấn đề bằng cách sử dụng OOP thuần túy?
  • Kiểu chức năng được giới thiệu trong Java 8 giúp chúng ta giảm khoảng cách giữa logic nghiệp vụ và mã. Nó cho phép chúng ta kể câu chuyện một cách tự nhiên ở cấp độ cao hơn. Thay vì nói bạn muốn làm như thế nào, bạn có thể nói bạn muốn làm gì.

  • Mã trở nên sạch hơn và ngắn gọn hơn.

  • Hàm bậc cao cho phép chúng ta:

    • Gửi chức năng đến các chức năng khác
    • Tạo các hàm bên trong các hàm khác
    • Trả về hàm từ các hàm khác

    Đây là một thắng lợi lớn cho Java, nơi chúng ta cần gửi, tạo và trả về các đối tượng để thực hiện việc này. Chúng ta sẽ có thể viết mã đáng tin cậy hơn, tập trung hơn và dễ sử dụng lại hơn.

  • Nhờ lambdas, chúng ta có thể thực hiện các phép tính lười biếng. Khi một biểu thức lambda được gửi dưới dạng đối số của phương thức, trình biên dịch sẽ đánh giá nó khi nó được gọi trong phương thức. Điều này khác với các đối số phương thức thông thường, được đánh giá ngay lập tức.

  • Lambdas làm cho việc viết bài kiểm tra đơn vị trở nên thú vị. Chúng cho phép chúng tôi tạo các bài kiểm tra nhẹ, rõ ràng, kích thước nhỏ và viết nhanh. Chúng ta có thể root mã đang được thử nghiệm bằng cách sử dụng lambdas. Điều này cho phép chúng tôi kiểm tra xem tất cả các loại kịch bản sẽ ảnh hưởng đến mã như thế nào.

  • Các mẫu mới để học.

  • Và nhiều hơn nữa!

Nhưng đủ nước, trong bài viết này chúng ta sẽ xem xét các giải pháp thay thế cho chu trình truyền thống. Tất nhiên, chu kỳ rất linh hoạt, nhưng điều này không phải không có giá. break, thay đổi đáng kể hành vi của vòng lặp, buộc chúng ta không chỉ hiểu mã đang cố gắng đạt được điều gì continuereturncòn phải hiểu cách vòng lặp hoạt động. Bây giờ chúng ta sẽ xem cách chuyển đổi vòng lặp thành mã ngắn gọn và dễ đọc hơn.

Hãy để mã hóa bắt đầu!

Chúng tôi sẽ làm việc với các bài viết. Một bài viết có tiêu đề, tác giả và một số thẻ.
private class Article {

    private final String title;
    private final String author;
    private final List<String> tags;

    private Article(String title, String author, List<String> tags) {
        this.title = title;
        this.author = author;
        this.tags = tags;
    }

    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }

    public List<String> getTags() {
        return tags;
    }
}
Mỗi ví dụ sẽ chứa một giải pháp truyền thống sử dụng các vòng lặp và một giải pháp sử dụng các tính năng mới của Java 8. Trong ví dụ đầu tiên, chúng tôi muốn tìm bài viết đầu tiên trong bộ sưu tập có thẻ “Java”. Chúng ta hãy xem xét một giải pháp sử dụng vòng lặp.
public Article getFirstJavaArticle() {

    for (Article article : articles) {
        if (article.getTags().contains("Java")) {
            return article;
        }
    }
    return null;
}
Bây giờ hãy giải quyết vấn đề bằng cách sử dụng các thao tác từ API Stream.
public Optional<Article> getFirstJavaArticle() {
    return articles.stream()
        .filter(article -> article.getTags().contains("Java"))
        .findFirst();
    }
Khá tuyệt phải không? Trước tiên, chúng tôi sử dụng thao tác filterđể tìm tất cả các bài viết có thẻ “Java”, sau đó chúng tôi sử dụng thao tác này findFirst()để lấy lần xuất hiện đầu tiên. Vì các luồng rất lười và bộ lọc trả về một luồng nên phương pháp này sẽ chỉ xử lý các phần tử cho đến khi tìm thấy kết quả khớp đầu tiên. Bây giờ, hãy lấy tất cả các bài viết được gắn thẻ “Java” thay vì chỉ bài viết đầu tiên. Đầu tiên là giải pháp sử dụng vòng lặp.
public List<Article> getAllJavaArticles() {

    List<Article> result = new ArrayList<>();

    for (Article article : articles) {
        if (article.getTags().contains("Java")) {
            result.add(article);
        }
    }
    return result;
}
Giải pháp sử dụng các hoạt động truyền phát.
public List<Article> getAllJavaArticles() {
    return articles.stream()
        .filter(article -> article.getTags().contains("Java"))
        .collect(Collectors.toList());
    }
Trong ví dụ này, chúng tôi đã sử dụng một thao tác collectđể rút ngắn luồng kết quả, thay vì khai báo một bộ sưu tập và thêm rõ ràng các mục nhập khớp. Càng xa càng tốt. Đã đến lúc đưa ra những ví dụ sẽ làm cho API Stream thực sự tỏa sáng. Hãy nhóm tất cả các bài viết theo tác giả. Như thường lệ, chúng ta bắt đầu với giải pháp sử dụng vòng lặp:
public Map<String, List<Article>> groupByAuthor() {

    Map<String, List<Article>> result = new HashMap<>();

    for (Article article : articles) {
        if (result.containsKey(article.getAuthor())) {
            result.get(article.getAuthor()).add(article);
        } else {
            ArrayList<Article> articles = new ArrayList<>();
            articles.add(article);
            result.put(article.getAuthor(), articles);
        }
    }
    return result;
}
Chúng ta có thể tìm ra giải pháp rõ ràng cho vấn đề này bằng cách sử dụng các hoạt động truyền phát không?
public Map<String, List<Article>> groupByAuthor() {
    return articles.stream()
        .collect(Collectors.groupingBy(Article::getAuthor));
}
Tuyệt vời! Bằng cách sử dụng một phép toán groupingByvà một tham chiếu phương thức getAuthor(), chúng ta có được mã rõ ràng và dễ đọc. Bây giờ chúng ta hãy tìm phần còn lại của các thẻ được sử dụng trong bộ sưu tập. Hãy bắt đầu với một ví dụ về vòng lặp:
public Set<String> getDistinctTags() {

    Set<String> result = new HashSet<>();

    for (Article article : articles) {
        result.addAll(article.getTags());
    }
    return result;
}
Được rồi, hãy xem cách chúng ta có thể giải quyết vấn đề này bằng cách sử dụng các thao tác truyền phát:
public Set<String> getDistinctTags() {
    return articles.stream()
        .flatMap(article -> article.getTags().stream())
        .collect(Collectors.toSet());
}
Mát mẻ! flatmapgiúp chúng tôi sắp xếp danh sách thẻ thành một luồng kết quả duy nhất, sau đó chúng tôi sử dụng luồng này collectđể tạo tập hợp trả về.

Khả năng vô tận

Đây là 4 ví dụ về cách thay thế vòng lặp bằng mã dễ đọc hơn. Hãy nhớ kiểm tra API Stream vì bài viết này chỉ mới sơ lược. Việc nắm vững phong cách chức năng mới của Java sẽ là một thách thức đối với các nhà phát triển OOP, nhưng đó là một thách thức cần được đón nhận. Tôi thậm chí còn đi xa hơn và nói rằng bạn nên học một ngôn ngữ lập trình hàm thuần túy. Bằng cách này bạn có thể hiểu đầy đủ các khả năng và sức mạnh mà nó cung cấp. Tôi nghĩ điều này sẽ giúp bạn hiểu lập trình chức năng ở một cấp độ khác. Vì vậy, hãy học lập trình chức năng cùng với OOP cũ và sử dụng cả hai để viết mã thậm chí còn tốt hơn! Bản dịch kết hợp miễn phí của hai bài viết - Tại sao bạn nên sử dụng lập trình chức năng trong Java 8Tránh xa các vòng lặp trong Java 8
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION