Hỏi đáp về try-catch-finally

Mọi người cho mình hỏi, nếu mà trong catch mình thực hiện bắt lỗi hết tất cả các lỗi có thể xảy ra, ví dụ như:

try
{
    ... //code causes error
}
catch (Exception e)
{
   ...//handle all exceptions
}

Thì việc sử dụng finally có ý nghĩa không ạ. Bởi vì finally dù trong try có lỗi hay không thì trong khối finally vẫn thực thi. Vậy nếu mình không viết finally mà ném code hẳn ra bên ngoài liệu có sao không ạ. Em cảm ơn mn đã giải đáp !

The Finally clause always forces your app to return to the Finally block and continue from there. Useful if, for example, you still have something to do afterward, before your app terminates (e.g. the last statement 'System.out.println(fin+" is copied to "+fout) will be invoked before TestX exits).
reopend:
example

import java.io.*;
public class TestX {
  private void copy(String fin, String fout) throws Exception {
    try (FileOutputStream fo = new FileOutputStream(fout);
         FileInputStream fi = new FileInputStream(fin);) {
         byte[] all = new byte[fi.available()];
         int n = fi.read(all);
         fo.write(all, 0, n);
         fi.close();
         fo.close();
    } catch (Exception ex) {
      System.out.println("Exception:"+ex.toString());
    } finally {
      System.out.println(fin+" is copied to "+fout);
    }
  }
  public static void main(String... parms) throws Exception {
    (new TestX()).copy(parms[0], parms[1]);
  }
}

giả sử thế này, bạn mở 1 file có dữ liệu là số. nếu file thành công, bạn parse data trong file đó thành số và trả về số trong file đó.

nếu chẳng may file đó có dữ liệu không phải là số -> bạn muốn throw exception cho người dùng.
và quan trọng là bạn không muốn file được close cho tới khi người dùng biết được việc file này thành công hay thất bại.

giả sử file luôn tồn tại nên mình sẽ bỏ qua đoạn mở file

var f = openFile("abc.data", "r")
var data = f.read();
try {
  var value = tryParse(data);
  return value;
} catch (Exception e) {
  throw e;
}

câu hỏi đặt ra là, làm sao bạn có thể đóng cái file f sau khi return?
thì khi này finally sẽ giúp bạn làm điều đó.

var f = openFile("abc.data", "r")
var data = f.read();
try {
  var value = tryParse(data);
  return value;
} catch (Exception e) {
  throw e;
} finally {
  f.close();
}

chung quy, finally thường sẽ giúp bạn dọn dẹp các đoạn code trong khối try-catch, sau khi xong việc. việc dọn dẹp có thể là đóng file, đóng connection, v.v
và mình đọc code thì “thường” thấy nó được đặt ở cuối hàm nhằm để dọn dẹp 1 hàm luôn.

lưu ý là finally “thường” được dùng như vậy, chứ không phải luôn luôn.


và vì finally thường là để “dọn dẹp”, nên nếu phần try-catch của bạn ở nằm ở giữa 1 hàm. lấy ví dụ trên, bạn lấy con số đó ra và cộng trừ nhân chia chẳng hạn. bạn không cần dọn dẹp gì thì bạn không cần finally cũng được.

chung quy khi bạn xài finally, hãy nghĩ rằng bạn muốn hay không chạy 1 đoạn code sau khối try-catch bất kể là try hay catch.
nếu có -> bạn hỏi tiếp là bạn có thể đặt đoạn code đó sau khối try-catch được không? như thế này

try {
...
} catch (...) {
  ...
}

// code sau try-catch ở đây

nếu được? thì bạn vứt ở sau đó cũng được.
còn nếu không -> xài finally block

try {
...
} catch (...) {
  ...
}

// code sau try-catch ở đây không được,
// vì ở trong try-catch có return, hàm sẽ kết thúc :/ 
->
try { ... }
catch (...) { }
finally { ... }
1 Like

try catch có làm giảm performace không nhỉ , thấy mọi người khuyên chỉ nên sài để bắt các lỗi mà không thể check , kiểu đọc file, đọc dữ liệu từ remote network, hay bị drop mạng

nếu không có lỗi, thì gần như sẽ không có performance impact.

Every execution takes time, which affects performance. The rule of thumb is: “Less codes = better performance”. That’s obvious, isn’t it? The more codes the CPU has to execute, the longer it takes, and of course other apps have to wait their turn. The finally block always forces the app to go back and continue at the finally block. In fact, without exception. And that obviously affects performance if the app is planless and excessively full of try-catch-finally.

Sadly, I have to stop you there. This isn’t always right, even if you are talking about CPU instructions, especially with CISC architecture.

1 Like

Because some people who don’t understand microprogramming and assembly codes often confuse source codes with executable (byte) codes, so the phrase “less codes = better performance” on related (byte)codes is “monstrous” for them :rofl:. The difference can be seen here:
TestZ.java generates more (byte) codes: 950 bytes (with -g:none)

public class TestZ {
  private boolean isEquals(int a, int b) throws Exception {
    int c = a - b;
    if (c < 0 || c > 0) return false;
    return true;
  }
  public static void main(String... parms) throws Exception {
    System.out.println("result of isEquals(10, 11):"+(new TestZ()).isEquals(10, 11));
  }
}

versus TestY.java that generates only 943 bytes (with -g:none)

public class TestY {
  private boolean isEquals(int a, int b) throws Exception {
    return a == b;
  }
  public static void main(String... parms) throws Exception {
    System.out.println("result of isEquals(10, 11):"+(new TestY()).isEquals(10, 11));
  }
}

Amazon started selling things that cost less than $10 and Bezos became a multimillionaire. It’s the mass that counts. The mass of such +7 bytes can slowdown the fastest computer. :rofl:

@Joe I agree with you…

Nói ví dụ ở frontend cho dễ hiểu. Là khi bấm submit form sẽ có cái loading xoay vòng vòng, và mình mong muốn kể cả API thành công hay thất bại thì đều tắt cái loading đó đi, vậy nên hàm tắt loading sẽ ở finally.
Finally dùng khi bất kể code trong try catch chạy thế nào thì cũng phải chạy vô nó. Có thể dùng để “dọn dẹp”, return sớm, hoặc chạy những function khác trong block mong muốn thôi.

Agree that in your example, with such dumb code, then less code is faster. But that doesn’t make the statement true for all other code.
As I said, even if you are talking about CPU instruction count, it’s still wrong. Since you are just mentioned about Java bytecode, so here is two examples (with pseudo-bytecode) for you:

// Less code
push a  // push number a to stack
push 3  // push number 3 to stack
imul    // calculate a*3 (two top numbers from stack)

vs

// More code
push a // push a to stack
push a // push a to stack
push a // push a to stack
iadd   // calculate a+a 
iadd   // calculate a+a+a or a*3

In this case, reference to https://www.jopdesign.com/doc/timing.pdf and you will see the less code version is indeed slower than the more code version.
If you still have no idea, here’s other reference for you: https://en.wikipedia.org/wiki/Loop_unrolling

cần gì phải low-level như thế. bubble sort vs merge sort là minh chứng rõ ràng rồi :flushed:
O(n^2) vs O(nlogn)

hoặc không linear và binary search với sorted array :kissing_heart:
O(n) vs O(logn)

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?