Apakah Java memiliki pernyataan use?


107

Apakah Java memiliki pernyataan using yang dapat digunakan saat membuka sesi dalam mode hibernasi?

Di C # itu seperti:

using (var session = new Session())
{


}

Jadi objek keluar dari ruang lingkup dan menutup secara otomatis.


4
"memungkinkan untuk menentukan ruang lingkup untuk suatu objek" Bukan itu yang usingdilakukannya. Cakupan bukanlah seumur hidup (dan usingjuga bukan tentang seumur hidup, tegasnya, karena Disposetidak menghancurkan memori objek.)
Joren

4
@Joren Komentar Anda semakin banyak dipilih, tetapi saya dapat melakukannya dengan sedikit info lagi. Andalah yang memperkenalkan ide "seumur hidup" lalu Anda mengatakan bahwa ini bukan tentang "seumur hidup". Scope adalah istilah yang digunakan dalam definisi dari pustaka msdn, mungkin saya menyalahgunakannya. Bagaimana Anda mendefinisikan using statement.
Jla

1
Cakupan mengacu pada area dalam kode di mana Anda dapat merujuk ke pengenal tanpa menggunakan nama yang sepenuhnya memenuhi syarat (variabel lokal, jenis, nama metode, dan semacamnya). Lifetime mengacu pada waktu di mana suatu objek atau variabel dapat diakses. Lihat blogs.msdn.com/b/ericlippert/archive/2009/08/03/...
Joren

2
Jadi misalnya, jika Anda memiliki variabel lokal dan menetapkan instance tipe nilai padanya, maka masa pakai nilai Anda akan berakhir saat masa pakai variabelnya berakhir. Namun jika Anda mengalokasikan sebuah objek, dan menyimpan referensi ke objek tersebut di lokal, maka masa pakai objek tersebut mungkin akan melampaui masa penyimpanannya, selama masih ada referensi ke objek tersebut di tempat lain. Adapun using, secara otomatis membuang objek di akhir cakupannya, tetapi tidak membatalkan alokasi objek - masa pakainya belum berakhir hingga semua referensinya menghilang.
Joren

Jawaban:


124

Java 7 memperkenalkan Manajemen Blok Sumber Daya Otomatis yang menghadirkan fitur ini ke platform Java. Versi Java sebelumnya tidak memiliki sesuatu yang mirip using.

Sebagai contoh, Anda dapat menggunakan penerapan variabel apa pun java.lang.AutoCloseabledengan cara berikut:

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

java.io.CloseableAntarmuka Java , yang diimplementasikan oleh aliran, secara otomatis meluas AutoCloseable, sehingga Anda sudah dapat menggunakan aliran di tryblok dengan cara yang sama seperti Anda menggunakannya di usingblok C # . Ini sama dengan C # using.

Mulai versi 5.0, Sesi Hibernasi diimplementasikanAutoCloseable dan dapat ditutup secara otomatis di blok ARM. Dalam versi sebelumnya dari SesiAutoCloseable Hibernasi tidak diterapkan . Jadi Anda harus menggunakan mode Hibernate> = 5.0 untuk menggunakan fitur ini.


1
"Untungnya" dengan Java 7 yang tersedia sekarang, jawaban ini tidak lagi benar (dan menurut saya blok ARM persis seperti usingitu).
Joachim Sauer

@ Joachim Sauer: Terima kasih. Saya memperbarui jawaban saya untuk mencerminkan berlalunya waktu. Untuk poin Anda blok ARM menjadi persis apa yang digunakan; pada saat saya menulis jawaban ini, bagi saya sepertinya blok ARM harus dicoba blok, sedangkan penggunaan dapat diterapkan ke sembarang blok. Melihatnya sekarang, sepertinya kata kunci do dapat digunakan di java untuk melakukannya. Apakah itu ditambahkan ke proposal baru-baru ini atau apakah saya melewatkannya untuk pertama kalinya? Juga OP menanyakan secara khusus tentang Sesi Hibernasi. AFAIK: Sesi Hibernasi masih belum diimplementasikan AutoCloseablesehingga mereka belum bisa menggunakan ARM.
Asaf

1
Tidak acara di 4.3 Hibernate JANGAN menerapkan AutoCloseable. docs.jboss.org/hibernate/orm/4.3/javadocs/index.html?org/… Saya rasa terserah setiap orang untuk menulis bungkusnya sendiri?
Andrei Rînea

1
Sesi tidak dapat mengimplementasikan AutoCloseable karena Session.close () mengembalikan Connection. Saya pikir ini adalah desain yang buruk tapi saya ragu ini akan pernah berubah.
usr-local-ΕΨΗΕΛΩΝ

@ usr-local-ΕΨΗΕΛΩΝ Saya baru saja membayangkan mereka akan mewajibkan siapa pun yang menggunakan hibernate untuk beralih ke java 7 jika mereka menerapkan antarmuka itu. AutoCloseabletidak ada sebelum java 7 kan?
Neil

31

Sebelum Java 7 , tidak ada fitur seperti itu di Java (untuk Java 7 ke atas lihat jawaban Asaph tentang ARM ).

Anda perlu melakukannya secara manual dan itu menyakitkan :

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

Dan itu hanya kode ketika tidak // Great codejuga hooray.close()dapat membuang pengecualian apapun.

Jika Anda benar-benar hanya ingin membatasi ruang lingkup variabel, blok kode sederhana dapat digunakan:

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

Tapi mungkin bukan itu yang Anda maksud.


1
Padanan Java Anda seharusnya tidak menjadi masalah jika // Great codemelontarkan pengecualian.
Cheeso

3
Ketika konstruktor melontarkan pengecualian, saya pikir kode Anda akan menghasilkan NullPointerException yang menutupi pengecualian asli.
Michael Borgwardt

@ Michael: sebenarnya contoh saya tidak dapat dikompilasi, karena horraymungkin belum diinisialisasi pada saat itu (diperbaiki sekarang).
Joachim Sauer

4
1 untuk blok sederhana mengambang yang dapat membatasi ruang lingkup. Namun, setiap kali saya melihatnya, itu hampir selalu merupakan indikator bahwa metode ini harus dipecah menjadi bagian yang lebih kecil.
Mark Peters

1
jika Anda ingin menangkap pengecualian apa pun dari konstruktor, Anda harus memilikinya di dalam blok percobaan. akan merepotkan untuk membungkus semuanya dalam percobaan / tangkapan lain.
THS



8

Padanan java terdekat adalah

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



2

Jika Anda tertarik dengan pengelolaan sumber daya, Project Lombok menawarkan @Cleanupanotasi. Diambil langsung dari situs mereka:

Anda dapat menggunakan @Cleanupuntuk memastikan resource tertentu secara otomatis dibersihkan sebelum jalur eksekusi kode keluar dari cakupan Anda saat ini. Anda melakukan ini dengan memberi anotasi deklarasi variabel lokal apa pun dengan @Cleanup anotasi seperti ini:

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

Akibatnya, di akhir cakupan tempat Anda berada, in.close()dipanggil. Panggilan ini dijamin untuk dijalankan dengan cara mencoba / konstruksi terakhir. Lihat contoh di bawah ini untuk melihat cara kerjanya.

Jika jenis objek yang ingin Anda bersihkan tidak memiliki close() metode, tetapi beberapa metode tanpa argumen lainnya, Anda dapat menentukan nama metode ini seperti:

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

Secara default, metode pembersihan dianggap close(). Metode pembersihan yang membutuhkan argumen tidak dapat dipanggil melalui @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();
    }
  }
}

Dengan 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

Silakan lihat Daftar Kata Kunci Java ini .

  1. The usingkata kunci sayangnya bukan bagian dari daftar.
  2. Dan juga tidak ada persamaan usingkata kunci C # melalui kata kunci lain seperti untuk sekarang di Java.

Untuk meniru "using"perilaku tersebut, Anda harus menggunakan try...catch...finallyblok, tempat Anda akan membuang sumber daya di dalamnya finally.


6
Fakta bahwa usingbukan kata kunci tidak berarti apa-apa. Fitur yang sama dapat (dan akan!) Diimplementasikan dengan kata kunci lain, seperti yang disebutkan @BalusC.
Joachim Sauer

1
Saya setuju! Tapi untuk saat ini, itu tidak ada, bukan? Itulah yang OP bertanya, apakah ada yang mirip sekarang. Senang mengetahui bahwa itu akan ada di rilis mendatang, tetapi itu tidak mengubah apa pun seperti untuk saat ini, dengan satu atau lain cara. Bagaimanapun, informasi yang diberikan oleh @BalusC sangat bagus! =)
Akankah Marcouiller

2
Saya setuju dengan itu, tetapi posting Anda sepertinya mengatakan bahwa fakta bahwa usingtidak ada dalam daftar kata kunci Java berarti fitur ini tidak ada dalam bahasa Java. Dan itu tidak benar.
Joachim Sauer

Jika ini yang tampaknya dikatakan oleh posting saya, maka saya akan mengedit untuk mencerminkan niat saya.
Akankah Marcouiller

Saya mengedit jawaban saya dengan menyatakan bahwa tidak ada usingkata kunci, dan juga tidak ada kesetaraan seperti untuk saat ini. Terima kasih @Joachim Sauer! =)
Akankah Marcouiller

1

Blok ARM , dari koin proyek akan ada di Java 7. Fitur ini dimaksudkan untuk membawa fungsionalitas yang mirip ke Java sebagai .Net menggunakan sintaks.


0

Untuk menjawab pertanyaan tentang membatasi ruang lingkup variabel, daripada berbicara tentang menutup / membuang variabel secara otomatis.

Di Java, Anda dapat menentukan cakupan anonim dan tertutup menggunakan tanda kurung kurawal. Ini sangat sederhana.

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

Variabel hoorayhanya tersedia dalam cakupan ini, bukan di luarnya.

Ini dapat berguna jika Anda memiliki variabel berulang yang hanya bersifat sementara.

Misalnya, masing-masing dengan index. Sama seperti itemvariabel ditutup di atas loop for (yaitu, hanya tersedia di dalamnya), indexvariabel ditutup di atas ruang lingkup anonim.

// 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
    }
}

Saya juga menggunakan ini kadang-kadang jika Anda tidak memiliki loop for untuk menyediakan lingkup variabel, tetapi Anda ingin menggunakan nama variabel generik.

{
    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);
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.