8 kỹ thuật tối ưu hóa mã nguồn Java khi lập trình Android

4
Dịch vụ dạy kèm gia sư lập trình

Có thể nói rằng Effective Java là một trong những cuốn sách hay cho dân lập trình android. Là một trong những cuốn “bí kíp” quan trọng nhất về tối ưu code Java mà các developer hay dùng để gối đầu giường cho mỗi giấc ngủ.

Như bạn cũng biết, để xây dựng ứng dụng android, bạn có thể sử dụng Java hoặc Kotlin. Tuy nhiên, phần lớn các dự án lớn vẫn đang sử dụng Java làm ngôn ngữ chính.

Vì thế đa số các lời khuyên trong cuốn sách này đều phù hợp với các bạn. Điều này có phải luôn đúng?

Thế nhưng thực tế lại có một số người cho rằng khá nhiều lời khuyên đưa ra trong cuốn sách khó có thể ứng dụng vào lập trình Android. Vì dù sao Java cho Android cũng có hơi khác so với Java EE, ngoài trừ tư tưởng OOP và ngữ pháp câu lệnh.

Vậy nghe theo ý kiến nào là đúng đây?

Tối ưu mã nguồn Java
Kỹ thuật tối ưu mã nguồn Java trong ứng dụng Android

Kỹ thuật tối ưu mã nguồn Java

Mình không có ý định liệt kê toàn bộ những lời khuyên trong cuốn sách mà mình chỉ tập trung vào những gì tinh túy nhất của cuốn sách. Hầu hết các lời khuyên này đều có thế ứng dụng rất tốt trong việc phát triển ứng dụng Android.

Theo kinh nghiệm của bản thân thì một số kiến thức được đưa ra trong cuốn sách này chưa thực sự phù hợp cho lập trình android. Vì không hẳn hầu hết các tính năng của Java đều được tối ưu khi sử dụng, ví dụ như Enums, Serialization…

Ngoài ra, chưa kể cơ chế hoạt động trên các thiết bị di động như máy ảo Davik/ART cũng khác so với JVM trên PC.

Còn lại thì phần lớn các mô hình được đưa ra trong sách có thể ứng dụng trong quá trình làm cho mã nguồn “sạch sẽ” và dễ maintaince hơn (thuật ngữ chuyên ngành như chúng ta đã biết là more cleaner and more maintainable)

💖 Xem thêm

Với các bạn đã từng đọc qua cuốn sách này thì đây chính là cơ hội để mọi người nhớ lại các “bí kíp” văn ôn võ luyện.

Còn các bạn nào chưa từng đọc qua sách này thì xin chúc mừng bạn. Đây chính là một trong những bí kíp nổi tiếng nhất trong giới võ lâm “Như lai thần chưởng” nhằm mục đích tu thành chánh đạo “Coding thập bát chưởng” đấy nhé.

Chúng ta bắt đầu thôi!

#1. Không cho tạo instance với Force non-instantiability

Nếu bạn không muốn một Object được tạo bằng từ khóa NEW thì hãy sử dụng Private constructor.

Kỹ thuật này đặc biệt hữu ích cho các Class chỉ chứa các hàm static. Ví dụ như các Utils class mà các bạn hay dùng đó.

class MovieUtils {
    private MovieUtils() {}
    static String titleAndYear(Movie movie) {
    [...]
    }
}

#2. Tối ưu mã nguồn Java với Static Factories

Kỹ thuật này nhằm mục đích đóng gói Object và hạn chế việc truy cập từ bên ngoài.

Lấy một ví dụ cụ thể để bạn dễ hiểu hơn. Như trong trường hợp chúng ta tránh việc cung cấp cách thức truy cập trực tiếp vào Database bởi vì tốn rất nhiều tài nguyên.

Do đó, đây chính là thời điểm mà chúng ta cần nghĩ đến việc ứng dụng Static Fatory Method. Trong đó, những hàm Factory Methods này có thể đặt tên khác với các hàm Constructor và tên Class (mặc định tên hàm Constructor chính là tên của Class).

Ngoài ra, chúng không bị áp đặt bắt buộc phải trả về một Instance của Object trong mỗi lần gọi. Ngoài ra, bạn có thể trả về một Subtype khác tùy thuộc vào mục đích bạn sử dụng.

class Movie {

    [...]

    public static Movie create(String title) {

    return new Movie(title);

    }

}
Lưu ý: Việc ứng dụng Static Factories Methods có thể gây nhiều trở ngại trong quá trình testing. Nếu chẳng may vướng vào trường hợp này, bạn có thể xem xét sử dụng Non-static Factories Methods hoặc Factory Interface để dễ dàng tạo ra Mock Test hơn.

👍 Dành cho bạn: 5 bí quyết để trở thành lập trình viên “bá đạo”

#3. Builders

Trường hợp bạn sở hữu một Object nhưng phải cần đến hơn 3 tham số trong hàm Constructor để tạo một Instance.

Lúc này bạn nên thử với Builder nhằm khởi tạo Object. Kỹ thuật này cũng giống như cách thiết kế Dialog, cũng dùng Builder để tạo Dialog.

Tuy nhiên, phải công nhận cách viết này cần khá nhiều dòng code java. Nhưng ngược lại sau khi tối ưu code Java sẽ rất dễ đọc và dễ mở rộng hơn.

class Movie {
    static Builder newBuilder() {
        return new Builder();
    }
    static class Builder {
        String title;
        Builder withTitle(String title) {
            this.title = title;
            return this;
        }
        Movie build() {
            return new Movie(title);
        }
    }

    private Movie(String title) {
    [...]    
    }
}
// Use like this:
Movie matrix = Movie.newBuilder().withTitle("The Matrix").build();

#4. Static member classes

Đừng quên khái niệm Static Class nếu như các bạn đang cần define một Inner Class mà không muốn phụ thuộc hay liên quan đến Outer Class.

Lý do nào khiến bạn phải làm như thế?

Bởi vì nếu không làm như vậy thì rất dễ dẫn đến việc mỗi Instance của Inner class sẽ được references đến Outer Class. Điều này thực sự sẽ mang đến nhiều phiền toái và có thể bị Memory Leak.

class Movie {
    [...]
    static class MovieAward {
        [...]
    }
}

#5. Generics (almost) everywhere

Các bạn nên đánh giá cao và biết ơn về việc Java cung cấp một cơ chế gọi là Type-safety.

Đây là cơ chế luôn giúp giảm đi tình trạng sử dụng Raw Types hay Object ít nhất có thể. Điều đó sẽ tối ưu code Java giúp cho phần Code java của bạn sẽ được hạn chế bớt lỗi sai khi biên dịch.

// Không nên
List movies = Lists.newArrayList();
movies.add("Hello!");
[...]
String movie = (String) movies.get(0);

// Nên
List<String> movies = Lists.newArrayList();
movies.add("Hello!");
[...]
String movie = movies.get(0);

// Không nên
List sort(List input) {
    [...]
}

// Nên
<T> List<T> sort(List<T> input) {
    [...]
}

Để Code có thể linh hoạt (flexible) hơn, bạn có thể sử dụng Bounded Wildcards (tạm dịch là “Ký hiệu đại diện“) nhằm mở rộng kiểu trả về mà bạn có thể chấp nhận được.

// Read stuff from collection - use "extends"
void readList(List<? extends Movie> movieList) {
    for (Movie movie : movieList) {
        System.out.print(movie.getTitle());
        [...]
    }
}

// Write stuff to collection - use "super"
void writeList(List<? super Movie> movieList) {
    movieList.add(Movie.create("Se7en"));
    [...]
}

#6. Trả về empty thay vì NULL

Theo kinh nghiệm bản thân, nếu một hàm bắt buộc trả về một List/Collection, mìnhkhuyên các bạn nên trả về một Collection rỗng thay vì trả về kết quả NULL.

Đây là cách tốt nhất giúp hạn chế phải hướng dẫn người sử dụng lại hàm đó cần phải xử lý NULL. Ngược lại nếu không làm sẽ dẫn đến NPE (NullPointerException).

List<Movie> latestMovies() {
    if (db.query().isEmpty()) {
        return Collections.emptyList();
    }
    [...]
}

#7. Không nên nối String bằng toán tử “+”

Trong trường hợp các bạn cần phải ghép nối nhiều String trở thành một String duy nhất, bạn hạn chế tối đa sử dụng toán tử “+” vì chúng có thể giảm hiệu suất.

Thay vì đó, các bạn nên sử dụng StringBuilder.

String latestMovieOneLiner(List<Movie> movies) {
    StringBuilder sb = new StringBuilder();
    for (Movie movie : movies) {
        sb.append(movie);
    }
    return sb.toString();
}

💖 Đừng bỏ lỡ: 6 lí do bạn không nên tự học code một mình

#8. Recoverable exceptions

Nếu trước đây bạn có thói quen xử lý Exception qua loa bằng cách Throw Exceptions. Mặc kệ Class “cha” xử lý thế nào cũng không quan trọng. Điều này sẽ làm ứng dụng của bạn sẽ rất dễ rơi vào trạng thái thông báo error một cách chung chung cho người dùng.

Do đó, người dùng khi gặp lỗi chỉ biết feedback lại rằng ứng dụng đã có lỗi nhưng không hiểu rõ được lỗi gì và cách xử lý thế nào.

Vì vậy, các bạn nên tập thói quen cụ thể hóa khi nào thì Exception này xảy ra và thông báo lỗi như nào. Tránh việc gây khó chịu cho người dùng mà ngay cả Developer cũng sẽ khó tìm và sửa lỗi ứng dụng.

List<Movie> latestMovies() throws MoviesNotFoundException {
    if (db.query().isEmpty()) {
        throw new MoviesNotFoundException();
    }
    [...]
}

Tạm kết

Theo cách nhìn của bản thân, bài viết này đơn thuần là nơi tổng hợp những lời khuyên phù hợp nhất cho lập trình viên và giải thích ngắn gọn nhất có mà cá nhân mình cảm thấy thực sự tâm đắc khi đọc qua cuốn sách Effective Java về tối ưu code Java.

Effective Java: A Programming Language Guide
Đây là cuốn sách cực hay giúp bạn tối ưu mã nguồn java hiệu quả. Sách viết dễ hiểu và dễ ứng dụng vào dự án.
Đến cha đẻ của ngôn ngữ lập trình Java còn thốt lên rằng: “Tôi ước mình có cuốn sách này 10 năm trước. Ngày đó tôi cứ nghĩ mình không cần một cuốn sách dạy Java nào, cho đến khi tôi biết cuốn sách này.”

Nhân tiện bài viết tối ưu mã nguồn java này, mình xin chia sẻ lại cho mọi người ☛ Tải sách

Mong rằng bài viết sẽ có thể giúp ích phần nào cho những người anh em trong ngành có thể dễ dàng xử lý công việc và cũng như trong quá trình nghiên cứu học tập.

Nếu thông tin trong bài viết còn điểm nào còn thiếu sót, hi vọng các anh em gửi cho mình feedback và thông tin bổ sung để mình có thể cập nhật nhanh chóng kiến thức mới nhất cho các anh em khác nhé.

Chào thân ái các chiến hữu và hẹn gặp lại !!!

Dịch vụ phát triển ứng dụng mobile giá rẻ - chất lượng
Bài trướcSử dụng Docker – những câu lệnh cơ bản (phần 2)
Bài tiếp theoTop 3 front end framework dành cho web developer tốt nhất 2023
Tên đầy đủ là Dương Anh Sơn. Tốt nghiệp ĐH Bách Khoa Hà Nội. Mình bắt đầu nghiệp coder khi mà ra trường chẳng xin được việc đúng chuyên ngành. Mình tin rằng chỉ có chia sẻ kiến thức mới là cách học tập nhanh nhất. Các bạn góp ý bài viết của mình bằng cách comment bên dưới nhé !

4
Bình luận. Cùng nhau thảo luận nhé!

avatar
  Theo dõi bình luận  
Mới nhất Cũ nhất Nhiều voted nhất
Thông báo
HOANG VAN NHA
Guest
HOANG VAN NHA

Hay lắm tiếp tục chia sẻ cho mọi người nhá.

TVD
Guest
TVD

Cảm ơn bạn đã chia sẻ!

Trần Long
Guest
Trần Long

Hay quá. Cám ơn tác giả nhé