• Java cơ bản
  • Javascript cơ bản
  • Spring Framework
  • Tutorial khác
  • Blog
Phú Phán's blog - trang cá nhân chia sẻ kinh nghiệm của một lập trình viênPhú Phán's blog - trang cá nhân chia sẻ kinh nghiệm của một lập trình viên
  • Java cơ bản
  • Javascript cơ bản
  • Spring Framework
  • Tutorial khác
  • Blog

Java cơ bản

  • Home
  • Java cơ bản
  • Khái niệm mutable và immutable object/class trong java

Khái niệm mutable và immutable object/class trong java

  • Posted by phuphan
  • Date February 29, 2020
  • Comments 0 comment
java mutable va immutable object va class

Java là ngôn ngữ lập trình hướng đối tượng(OOP), chính vì vậy làm việc với Java chúng ta sẽ thường xuyên làm việc với object. Các bạn có biết object trong java còn được phân loại thành 2 loại là mutable và immutable object. Trong bài này chúng ta sẽ tìm hiểu chi tiết hơn nhé, mấy cái khái niệm này hay quên lắm 😉.

Khái niệm mutable và immutable object

Mutable object có thể hiểu đơn giản là có thể thay đổi giá trị thuộc tính của chính object đó. Mỗi mutable object sẽ có nhiều thuộc tính trỏ đến nhiều vùng nhớ khác nhau. Mutable object có thể chìa ra vài method để ta có thể thay đổi giá trị thuộc tính hoặc trỏ đến vùng nhớ khác.

Immutable object là khái niệm cực kỳ cơ bản trong lập trình hướng đối tượng. khái niệm immutable object hoàn toàn ngược lại với mutable object, ta có thể hiểu nôm na là object không thể thay đổi thuộc tính của object.

Ưu và nhược điểm của immutable object

Ưu điểm

Nếu bạn chưa từng làm việc hoặc chưa nghe đến immutable, có lẽ bạn sẽ nghĩ nó là tính năng thừa. Tuy nhiên immutable mang đến rất nhiều lơị ích cho hệ thống. Cụ thể như sau:

Thứ nhất: hỗ trợ xây dựng hệ thống ổn định. Ưu điểm này đến từ chính đặc tính vốn có của Immutable là không thể thay đổi giá trị sau khi khởi tạo .

Lấy ví dụ về class Bank, đại diện cho một ngân hàng. Ta xét hoàn cảnh sau: khi cuộc khủng hoảng tài chính trôi qua, nhà băng không cho phép tài khoản người dùng có thẻ có giá trị số dư là âm. Để làm được điều này, người ta sẽ thêm một method kiểm tra và các luật sao cho khi có tài khoản bị âm, nó sẽ bắn ra IllegalArgumentException. Kiểu luật này gọi là invariant – luật bất biến.

public class BankAccount {
   // ...
    private void validate(long balance) {
        if (balance < 0) {
            throw new IllegalArgumentException("balance must not be negative:"+ balance);
        }

        //...
    }
    // ...
}

Trong một class thông thường, hàm validedate() có thể được gọi bất kì thời điểm nào nếu có xảy ra thay đổi số dư tài khoản. Tuy nhiên với immutable class, ta chỉ cần gọi validate() một lần duy nhất trong constructor.

public class BankAccount {
    public BankAccount(long balance) {
        validate(balance);
        this.balance = balance;
    }

    // ...
}

Không thể thay đổi giá trị của Immutable object. Điều này đúng với một object kể từ lúc nó được khởi tạo cho đến khi bị “dọn dẹp” bởi Garbage Collector. Mỗi khi số dư tài khoản bị thay đổi, một object mới sẽ được tạo ra. Vì thế ta chỉ cần kiểm tra giá trị tài khoản tại thời điểm object tương ứng được khởi tạo. Đồng nghĩa với gọi validate() một lần duy nhất trong constructor. Từ đó, ta có thể tập trung các luật bất biến trong ứng dụng mà ta đang xây dựng và đảm bảo tính nhất quán cho các object trong suốt vòng đời của chúng.

Thứ hai, tính immutable có thể được áp dụng cho các hệ thống đặc thù yêu cầu “khả năng chịu lỗi” (fault-tolerance).

Hãy tưởng tượng bạn cần rút tiền từ ngân hàng. Tại thời điểm mà tài khoản của bạn bị trừ đi số tiền mà ATM sắp nhả ra thì xuất hiện lỗi. Như vậy với normal class, bạn đã mất tiền. Nhưng với immutable class, lỗi sẽ được bắn ra kèm theo đó là tài khoản của bạn không hề thay đổi trừ khi bạn đã nhận được tiền.

public ImmutableAccount withdraw(long amount) {

    long newBalance = newBalance(amount);

    return new ImmutableAccount(newBalance);

}

private long newBalance(long amount) {

    // exception during balance calculation

}

Immutable object không bao giờ rơi vào trạng thái phi nhất quán (inconsistence), ngay cả khi xảy ra exception. Điều này góp phần tăng tính ổn định cho hệ thống.

Thứ ba, tính immutable có thể được chia sẻ giữa các object.

java immutable object chia se thuoc tinh

Ví dụ: ta có một object kiểu Account, trong object Account, có thuộc tính kiểu Holder và Balance (tất nhiên chúng cũng là object).

Khi ta copy object Account, ta có thể để 2 bản thể đó sử dụng chung thuộc tính Balance. Và nếu ta thay đổi Balance ở một object Account, nó sẽ không ảnh hưởng tới object Account còn lại. Object còn lại tạo một bản thể (vẫn giữ tính Immutable) của class Account và 2 object cũ – mới này không hề liên quan đến nhau nữa.

Một Immutable object không cần copy constructor khi copy object. Immutable object có thể được chia sẻ tự do khi sử dụng thuật toán lock-free trong môi trường multithread.

Cuối cùng, immutable object là một lựa chọn sáng giá khi sử dụng làm key của Map hoặc làm element của Set.

Nhược điểm của tính Immutable

Nhược điểm lớn nhất của immutable là nó có nguy cơ tác động tiêu cực lên performance. Ta sẽ cần khởi tạo nhiều immutable object so với mutable object, và cứ mỗi object tạo ra thì tài nguyên dự trữ  của hệ thống lại vơi đi một chút.

Vì vậy, để tránh vấn đề đó ảnh hưởng tới quá trình xây dựng ứng dụng, ta cần khảo sát kỹ các yếu tố như: loại thiết bị triển khai ứng dụng, đặc điểm phần cứng của thiết bị đó, kích thước của ứng dụng… Kết quả khảo sát tổng hợp từ các yếu tố này sẽ giúp bạn có quyết định đúng đắn về việc có nên sử dụng immutable object hay không.

Tại sao lại dùng immutable object

Tuy sử dụng immutable có nhược điểm về performance như vậy nhưng cũng có những trường hợp immutable object lại mang lại những lợi ích to lớn. Và đây là lý do vì sao chúng ta cần sử dụng immutable object trong những trường hợp nhất định thông qua những ví dụ sau đây:

Ví dụ Immutable với String

Java immutable object string example
Java immutable object string example
// Khởi tạo str1 = "first"
String str1 = new String("first");
// Khởi tạo str2 tham chiếu tới str1
String str2 = str1;
// String là immutable, bất kì thao tác nào trên String đều tạo ra 1 đối tượng mới
// str1.concat("-second") sẽ trả về 1 đối tượng String mới có giá trị là "first-second"
str1 = str1.concat("-second");
System.out.println("str1: "+str1);
System.out.println("str2: "+str2);

Ví dụ Mutable với StringBuffer

java immutable object string buffer example
java immutable object string buffer example
// Khởi tạo str1 = "first"
StringBuffer str1 = new StringBuffer("first");
// Khởi tạo str2 tham chiếu tới str1
StringBuffer str2 = str1;
// StringBuffer là mutable, do đó khi append thì giá trị của nó sẽ thay đổi trên chính vùng nhớ ban dầu
str1.append("-second");
System.out.println("str1: "+str1);
System.out.println("str2: "+str2);

Thread safe

Trong những hệ thống đa luồng như server, game, … khi sử dụng immutable object ta sẽ không cần phải lo tới việc nhiều thread cùng làm thay đổi giá trị của 1 object

Chia sẻ object

Giống như ví dụ với String bên trên, ta thấy được sử dụng immutable sẽ tránh được sự thay đổi lẫn nhau khi đa tham chiếu (str1 và str2 cùng tham chiếu tới 1 vùng nhớ nhưng khi str1 thay đổi thì str2 sẽ không thay đổi)

Tính bất biến

Sử dụng các immutable object làm tham số của method sẽ không sợ nó bị thay đổi sau khi method kết thúc. Hoặc sử dụng immutable object để làm key trong HashMap hoặc đẩy vào HashTable mà không gặp vấn đề gì khi lấy ra.

Cách tạo và áp dụng immutable object

  • Phải là final class (không thể thừa kế bởi class khác)
  • Các field phải là private final
  • Không có các method làm thay đổi trạng thái của các field (Ví dụ: chỉ có hàm get, không có các hàm set)
  • Nếu có field nào là Object thì field đó cũng phải là 1 immutable Object hoặc khi khởi tạo/lấy ra field đó ta phải clone ra 1 bản khác.

Ví dụ mutable class

public class MutableClass {

    private String first_name;
    private String last_name;

    public MutableClass(String first_name, String last_name) {
        this.first_name = first_name;
        this.last_name = last_name;
    }

    //Mutator
    public String getFirstName() {
        return first_name;
    }

    public void setFirstName(String first_name) {
        this.first_name = first_name;
    }

    public String getLastName() {
        return last_name;
    }

    public void setLastName(String last_name) {
        this.last_name = last_name;
    }
}

Ví dụ immutable class

import java.util.Date;
public final class ImmutableClass {

    private String first_name;
    private String last_name;
    private Date dateOfBirth;

    public ImmutableClass(String first_name, String last_name, Date dob) {
        this.first_name = first_name;
        this.last_name = last_name;
        dateOfBirth = dob;
    }

    public String getFirstName() {
        return first_name;
    }

    public String getLastName() {
        return last_name;
    }

    public Date getDateOfBirth() {
        return dateOfBirth;
    }
}

Tag:immutable object, java cơ bản, mutable object

  • Share:
author avatar
phuphan

    Previous post

    Lớp String trong java và các hàm xử lý String(có ví dụ)
    February 29, 2020

    Next post

    Khởi tạo web application bằng Spring 5
    March 18, 2020

    You may also like

    Java string
    Lớp String trong java và các hàm xử lý String(có ví dụ)
    10 February, 2020

    Leave A Reply Cancel reply

    Your email address will not be published. Required fields are marked *

    Recent Posts

    • Khởi tạo web application bằng Spring 5
    • Khái niệm mutable và immutable object/class trong java
    • Lớp String trong java và các hàm xử lý String(có ví dụ)

    Recent Comments

      Archives

      • March 2020
      • February 2020

      Categories

      • Java cơ bản
      • Spring Framework

      Developed by Edinnova's team