Method toString() thuộc class java.lang.String, giá trị trả về mang kiểu dữ liệu String và cũng chính là giá trị của object đang gọi nó,.

Việc sử dụng method toString() một cách bừa bãi sẽ dẫn tới 2 hậu họa:

  • Tạo ra các ràng buộc vòng tròn nối đuôi nhau (circular dependencies)
  • Nguy cơ lỗi StackOverFlow

#1 Khởi nguồn

Để dễ hình dung, chúng ta cùng xét ví dụ sau, ví dụ của chung sta có 3 class là Account, Account Holder và Main:

Đầu tiên là class AccountHolder.java

package com.example.toString;

import java.util.ArrayList;

import java.util.List;

public class AccountHolder {

   private String name;

   private List<Account> accList=new ArrayList<Account>();

   public void addAccount(Account acc){

      accList.add(acc);

   }

   public String getName() {

      return name;

   }

   public void setName(String name) {

      this.name = name;

   }

   @Override

   public String toString() {

      return "AccountHolder [name=" + name + ", accList=" + accList + "]";

   }

}

Tiếp đó là Account.java

package com.example.toString;

public class Account {

   private String accNumber;

   private String accType;

   private AccountHolder holder;

   public String getAccNumber() {

      return accNumber;

   }

   public void setAccNumber(String accNumber) {

      this.accNumber = accNumber;

   }

   public String getAccType() {

      return accType;

   }

   public void setAccType(String accType) {

      this.accType = accType;

   }

   public AccountHolder getHolder() {

      return holder;

   }

   public void setHolder(AccountHolder holder) {

      this.holder = holder;

   }

   @Override

   public String toString() {

      return "Account [accNumber=" + accNumber + ", accType=" + accType

              + ", holder=" + holder + "]";

   }

}

Cuối cùng là Main.java

package com.example.toString;

public class Main {

   public static void main(String[] args) {

      AccountHolder ach = new AccountHolder();

      ach.setName("Shamik Mitra");

      Account acc = new Account();

      acc.setAccNumber("100sm");

      acc.setAccType("Savings");

      acc.setHolder(ach);

      ach.addAccount(acc);

      System.out.println(ach);

   }

}

Bạn hãy quan sát kĩ 3 class này, nhận diện các vấn đề mà chúng đang gặp phải, ghi ra giấy rồi chuyển tới phần tiếp theo của bài viết.

Tham khảo các khóa học lập trình online, onlab, và thực tập lập trình tại TechMaster

#2 Vấn đề

Có lẽ bạn đoán đúng, 2 đoạn code trên bị lỗi StackOverFlow. Thực ra chúng chính là code của một cậu Junior được tôi review.

2 class AccountHolder và Account tạo ra 2 object tương ứng. AccountHolder sẽ giữ thông tin của Account, và trong Account object có một tham chiếu tới Account Holder. Đây là một kịch bản phổ biến khi chúng ta làm việc với JPA entity. Tuy nhiên vấn đề phát sinh lỗi StackOverFlow lại nằm ở chỗ cậu Junior này đã vô tình generate method toString() một cách tự động thông qua tính năng auto code generation của IDE. Và hậu quả là các lời gọi hàm nối đuôi nhau liên tục dẫn tới lỗi StackOverFlow.

Bạn hãy để ý kĩ, method toString() trong class AccountHolder sẽ in ra danh sách các Account, do đó method này sẽ gọi đến toString() trong class Account. Thật không may, method toString() trong class Account lại tiếp tục gọi tới AccountHolder. Các lời gọi cứ nối đuôi nhau cho đến khi xảy ra lỗi StackOverFlow.

Tại sao cậu Junior lại không phát hiện ra lỗi này? Bởi các đoạn code tiếp theo của cậu ta không hề gọi tới toString() của một trong 2 class Account, AccountHolder.

#3 Khắc phục và phòng chống

Điều tôi muốn cảnh báo mọi người thông qua trường hợp này đó là hãy luôn cẩn thận khi lập trình. Thế giới bug có rất nhiều trường hợp không thể nhìn thấy bằng mắt thường.

Đối với các trường hợp nghi ngờ tồn tại các ràng buôc nối đuôi nhau, lập trình viên nên sử dụng các tool có khả năng tự động detect các vị trí đó.

Tuyệt đối tránh việc in ra (in ra màn hình console hoặc bất cứ nơi nào khác) các biến không phải là biến của class đó. Cẩn thận hơn nữa, lập trình viên không nên in các biến liên quan tới những mối quan hệ có-một (Has - a) giữa các class.

Techmaster via Dzone