Java có câu lệnh using không?


107

Java có câu lệnh using có thể được sử dụng khi mở một phiên ở chế độ ngủ đông không?

Trong C #, nó giống như:

using (var session = new Session())
{


}

Vì vậy, đối tượng đi ra khỏi phạm vi và tự động đóng lại.


4
"cho phép xác định phạm vi cho một đối tượng" Đó không phải là những gì using. Phạm vi không phải là thời gian tồn tại (và usingcũng không phải là suốt đời, nói đúng ra, cũng như Disposekhông phá hủy bộ nhớ của đối tượng.)
Joren

4
@Joren Bình luận của bạn đang được bình chọn nhưng tôi có thể làm với một chút thông tin. Bạn là người giới thiệu ý tưởng "suốt đời" thì bạn nói nó không phải là về "suốt đời". Phạm vi là thuật ngữ được sử dụng trong định nghĩa từ thư viện msdn, có lẽ tôi đã sử dụng sai. Làm thế nào bạn sẽ xác định using statement.
Jla

1
Phạm vi đề cập đến khu vực trong mã mà bạn có thể tham chiếu đến một định danh mà không cần sử dụng tên đủ điều kiện của nó (biến cục bộ, kiểu, tên phương thức, v.v.). Thời gian tồn tại đề cập đến thời gian mà một đối tượng hoặc biến có thể truy cập được. Xem blog.msdn.com/b/ericlippert/archive/2009/08/03/…
Joren

2
Vì vậy, ví dụ: nếu bạn có một biến cục bộ và gán một cá thể kiểu giá trị cho nó, thì thời gian tồn tại của giá trị của bạn sẽ kết thúc khi thời gian tồn tại của biến của nó kết thúc. Nhưng nếu bạn đã cấp phát một đối tượng và lưu trữ một tham chiếu đến nó trong cục bộ, thì thời gian tồn tại của đối tượng đó rất có thể kéo dài qua thời gian lưu trữ của nó, miễn là vẫn còn một số tham chiếu đến đối tượng ở nơi khác. Đối với việc using, nó tự động loại bỏ đối tượng ở cuối phạm vi của nó, nhưng nó không phân bổ đối tượng - thời gian tồn tại của nó sẽ không kết thúc cho đến khi tất cả các tham chiếu của nó biến mất.
Joren

Câu trả lời:


124

Java 7 đã giới thiệu Quản lý khối tài nguyên tự động mang tính năng này lên nền tảng Java. Các phiên bản trước của Java không có bất cứ điều gì giống nhau using.

Ví dụ: bạn có thể sử dụng bất kỳ triển khai biến nào java.lang.AutoCloseabletheo cách sau:

try(ClassImplementingAutoCloseable obj = new ClassImplementingAutoCloseable())
{
    ...
}

java.io.CloseableGiao diện của Java , được thực thi bởi các luồng, tự động mở rộng AutoCloseable, vì vậy bạn đã có thể sử dụng các luồng trong một trykhối giống như cách bạn sử dụng chúng trong một usingkhối C # . Điều này tương đương với C # using.

Kể từ phiên bản 5.0, Hibernate Sessions triển khaiAutoCloseable và có thể được đóng tự động trong các khối ARM. Trong các phiên bản trước của Hibernate Session không thực hiện đượcAutoCloseable . Vì vậy, bạn cần phải ở chế độ Hibernate> = 5.0 để sử dụng tính năng này.


1
"May mắn thay" với Java 7 hiện có sẵn, câu trả lời này không còn đúng nữa (và tôi nghĩ rằng các khối ARM chính xác là những gì usinghiện có).
Joachim Sauer,

@Joachim Sauer: Cảm ơn. Tôi đã cập nhật câu trả lời của mình để phản ánh thời gian trôi qua. Đối với quan điểm của bạn về các khối ARM chính xác là những gì đang sử dụng; Vào thời điểm tôi viết câu trả lời này, tôi có vẻ như khối ARM phải là khối thử, trong khi việc sử dụng có thể được áp dụng cho bất kỳ khối tùy ý nào. Nhìn vào nó bây giờ, có vẻ như từ khóa do có thể được sử dụng trong java để thực hiện điều này. Nó đã được thêm vào đề xuất gần đây hay tôi đã bỏ lỡ nó lần đầu tiên? OP cũng hỏi cụ thể về Hibernate Sessions. AFAIK: Hibernate Sessions vẫn không triển khai AutoCloseablenên họ chưa thể sử dụng ARM.
Asaph

1
Không phải sự kiện trong 4.3 Hibernate KHÔNG thực hiện AutoClosable. docs.jboss.org/hibernate/orm/4.3/javadocs/index.html?org/… Tôi đoán mọi người viết trình bao bọc của riêng mình?
Andrei Rînea

1
Phiên không thể triển khai Tự động đóng vì Session.close () trả về một Kết nối. Tôi nghĩ đây là một thiết kế tồi nhưng tôi nghi ngờ điều này sẽ không bao giờ được thay đổi.
usr-local-ΕΨΗΕΛΩΝ

@ usr-local-ΕΨΗΕΛΩΝ Tôi chỉ biết rằng họ sẽ yêu cầu bất kỳ ai sử dụng chế độ ngủ đông chuyển sang java 7 nếu họ triển khai giao diện đó. AutoCloseablekhông tồn tại trước java 7?
Neil

31

Trước Java 7 , không có tính năng này trong Java (đối với Java 7 trở lên, hãy xem câu trả lời của Asaph về ARM ).

Bạn cần phải làm điều đó theo cách thủ công và đó là một nỗi đau :

AwesomeClass hooray = null;
try {
  hooray = new AwesomeClass();
  // Great code
} finally {
  if (hooray!=null) {
    hooray.close();
  }
}

Và đó chỉ là mã khi không // Great codevà cũng không hooray.close()thể ném bất kỳ ngoại lệ nào.

Nếu bạn thực sự chỉ muốn giới hạn phạm vi của một biến, thì một khối mã đơn giản sẽ thực hiện công việc:

{
  AwesomeClass hooray = new AwesomeClass();
  // Great code
}

Nhưng đó có lẽ không phải là ý của bạn.


1
Java tương đương của bạn sẽ không có vấn đề gì nếu // Great codeném một ngoại lệ.
Cheeso

3
Khi phương thức khởi tạo ném một ngoại lệ, tôi nghĩ rằng mã của bạn sẽ dẫn đến một NullPointerException che đi ngoại lệ ban đầu.
Michael Borgwardt

@Michael: thực ra ví dụ của tôi sẽ không biên dịch, vì horraycó thể chưa được khởi tạo tại thời điểm đó (đã sửa ngay bây giờ).
Joachim Sauer,

4
+1 cho các khối đơn giản nổi có thể giới hạn phạm vi. Tuy nhiên, bất cứ khi nào tôi nhìn thấy những điều này, nó hầu như luôn luôn là một chỉ báo rằng phương pháp nên được chia thành các phần nhỏ hơn.
Mark Peters

1
nếu bạn muốn bắt bất kỳ ngoại lệ nào từ hàm tạo, bạn phải có nó bên trong khối try. sẽ rất rườm rà nếu gói toàn bộ trong một lần thử / bắt khác.
ths


8

Về mặt kỹ thuật:

DisposableObject d = null;
try {
    d = new DisposableObject(); 
}
finally {
    if (d != null) {
        d.Dispose();
    }
}

2
Không phải là cách tốt nhất để làm điều đó. stackoverflow.com/questions/1909662/…
Mark Byers

5
Điều này về cơ bản sẽ tương đương. Tôi không quan tâm nếu đó là cách tốt nhất.
ChaosPandion

2
Được viết như một lập trình viên C # thực thụ. ;)
Neil

8

Tương đương java gần nhất là

AwesomeClass hooray = new AwesomeClass();
try{
    // Great code
} finally {
    hooray.dispose(); // or .close(), etc.
}



2

Nếu bạn quan tâm đến quản lý tài nguyên, Project Lombok cung cấp @Cleanupchú thích. Lấy trực tiếp từ trang web của họ:

Bạn có thể sử dụng @Cleanupđể đảm bảo một tài nguyên nhất định được tự động dọn dẹp trước khi đường dẫn thực thi mã thoát khỏi phạm vi hiện tại của bạn. Bạn thực hiện việc này bằng cách chú thích bất kỳ khai báo biến cục bộ nào với @Cleanup chú thích như sau:

@Cleanup InputStream in = new FileInputStream("some/file");

Kết quả là, ở cuối phạm vi bạn đang ở, in.close()được gọi. Cuộc gọi này được đảm bảo chạy bằng cách xây dựng thử / cuối cùng. Hãy xem ví dụ dưới đây để xem cách này hoạt động như thế nào.

Nếu loại đối tượng bạn muốn dọn dẹp không có close() phương thức, nhưng một số phương thức không đối số khác, bạn có thể chỉ định tên của phương thức này như sau:

@Cleanup("dispose") org.eclipse.swt.widgets.CoolBar bar = new CoolBar(parent, 0);

Theo mặc định, phương pháp dọn dẹp được coi là close(). Phương thức dọn dẹp có tham số không thể được gọi qua @Cleanup.

Vanilla Java

import java.io.*;

public class CleanupExample {
  public static void main(String[] args) throws IOException {
    InputStream in = new FileInputStream(args[0]);
    try {
      OutputStream out = new FileOutputStream(args[1]);
      try {
        byte[] b = new byte[10000];
        while (true) {
          int r = in.read(b);
          if (r == -1) break;
          out.write(b, 0, r);
        }
      } finally {
        out.close();
      }
    } finally {
      in.close();
    }
  }
}

Với Lombok

import lombok.Cleanup;
import java.io.*;

public class CleanupExample {
  public static void main(String[] args) throws IOException {
    @Cleanup InputStream in = new FileInputStream(args[0]);
    @Cleanup OutputStream out = new FileOutputStream(args[1]);
    byte[] b = new byte[10000];
    while (true) {
      int r = in.read(b);
      if (r == -1) break;
      out.write(b, 0, r);
    }
  }
}


1

Vui lòng xem Danh sách Từ khóa Java này .

  1. Các usingtừ khóa là không may không nằm trong danh sách.
  2. Và cũng không có sự tương đương của usingtừ khóa C # thông qua bất kỳ từ khóa nào khác như hiện nay trong Java.

Để bắt chước "using"hành vi như vậy , bạn sẽ phải sử dụng một try...catch...finallykhối, nơi bạn sẽ xử lý các tài nguyên bên trong finally.


6
Thực tế usingkhông phải là một từ khóa không có nghĩa là một điều. Tính năng tương tự có thể được (và sẽ được!) Được triển khai với một từ khóa khác, như @BalusC đã đề cập.
Joachim Sauer,

1
Tôi đồng ý! Nhưng hiện tại, nó không tồn tại, đúng không? Đó là những gì OP đã hỏi, nếu có điều gì đó giống nhau vừa rồi. Thật tốt khi biết rằng nó sẽ tồn tại trong các bản phát hành trong tương lai, nhưng điều đó không thay đổi một thứ như bây giờ, bằng cách này hay cách khác. Dù sao, thông tin được cung cấp bởi @BalusC là rất tốt! =)
Sẽ Marcouiller

2
Tôi đồng ý với điều đó, nhưng bài đăng của bạn dường như nói rằng thực tế usingkhông có trong danh sách các từ khóa Java có nghĩa là tính năng này không có trong ngôn ngữ Java. Và điều đó không đúng.
Joachim Sauer,

Nếu đây là những gì bài viết của tôi muốn nói, thì tôi sẽ chỉnh sửa để phản ánh ý định của tôi.
Will Marcouiller

Tôi đã chỉnh sửa câu trả lời của mình chỉ định rằng không có usingtừ khóa nào và cũng không có từ khóa nào tương đương như bây giờ. Cảm ơn @Joachim Sauer! =)
Sẽ Marcouiller


0

Để trả lời câu hỏi liên quan đến giới hạn phạm vi của một biến, thay vì nói về việc tự động đóng / loại bỏ các biến.

Trong Java, bạn có thể xác định các phạm vi đóng, ẩn danh bằng cách sử dụng dấu ngoặc nhọn. Nó cực kỳ đơn giản.

{
   AwesomeClass hooray = new AwesomeClass()
   // Great code
}

Biến hooraychỉ có sẵn trong phạm vi này và không có bên ngoài nó.

Điều này có thể hữu ích nếu bạn có các biến lặp lại chỉ là tạm thời.

Ví dụ, mỗi mục có chỉ mục. Giống như itembiến được đóng trong vòng lặp for (tức là chỉ có sẵn bên trong nó), indexbiến được đóng trong phạm vi ẩn danh.

// first loop
{
    Integer index = -1;
    for (Object item : things) {index += 1;
        // ... item, index
    }
}

// second loop
{
    Integer index = -1;
    for (Object item : stuff) {index += 1;
        // ... item, index
    }
}

Tôi cũng sử dụng điều này đôi khi nếu bạn không có vòng lặp for để cung cấp phạm vi biến, nhưng bạn muốn sử dụng tên biến chung.

{
    User user = new User();
    user.setId(0);
    user.setName("Andy Green");
    user.setEmail("andygreen@gmail.com");
    users.add(user);
}

{
    User user = new User();
    user.setId(1);
    user.setName("Rachel Blue");
    user.setEmail("rachelblue@gmail.com");
    users.add(user);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.