Java มีคำสั่งใช้หรือไม่?


108

Java มีคำสั่งการใช้งานที่สามารถใช้เมื่อเปิดเซสชันในโหมดไฮเบอร์เนตหรือไม่?

ใน C # เป็นสิ่งที่ชอบ:

using (var session = new Session())
{


}

ดังนั้นวัตถุจึงอยู่นอกขอบเขตและปิดโดยอัตโนมัติ


4
"อนุญาตให้กำหนดขอบเขตสำหรับวัตถุ" นั่นไม่ใช่สิ่งที่usingทำ ขอบเขตไม่ใช่อายุการใช้งาน (และusingไม่เกี่ยวกับอายุการใช้งานด้วยพูดอย่างเคร่งครัดเนื่องจากDisposeไม่ทำลายความทรงจำของวัตถุ)
Joren

4
@Joren ความคิดเห็นของคุณกำลังได้รับการโหวต แต่ฉันสามารถทำได้ด้วยข้อมูลเพิ่มเติมเล็กน้อย คุณเป็นคนแนะนำแนวคิด "อายุการใช้งาน" แล้วคุณบอกว่ามันไม่เกี่ยวกับ "อายุการใช้งาน" ขอบเขตเป็นคำที่ใช้ในคำจำกัดความจากไลบรารี msdn บางทีฉันอาจใช้ผิด คุณจะกำหนดไฟล์using statement.
Jla

1
ขอบเขตหมายถึงพื้นที่ในโค้ดที่คุณสามารถอ้างถึงตัวระบุได้โดยไม่ต้องใช้ชื่อที่มีคุณสมบัติครบถ้วน (ตัวแปรโลคัลประเภทชื่อวิธีการและอื่น ๆ ) อายุการใช้งานหมายถึงเวลาที่วัตถุหรือตัวแปรสามารถเข้าถึงได้ ดูblogs.msdn.com/b/ericlippert/archive/2009/08/03/…
Joren

2
ตัวอย่างเช่นหากคุณมีตัวแปรโลคัลและกำหนดอินสแตนซ์ประเภทค่าให้กับมันอายุการใช้งานของค่าของคุณจะสิ้นสุดลงเมื่ออายุการใช้งานของตัวแปรสิ้นสุดลง แต่ถ้าคุณจัดสรรออบเจ็กต์และจัดเก็บข้อมูลอ้างอิงไว้ในโลคัลอายุการใช้งานของอ็อบเจ็กต์นั้นอาจยืดออกไปตามอายุการจัดเก็บได้เป็นอย่างดีตราบใดที่ยังมีการอ้างอิงถึงอ็อบเจ็กต์ที่อื่นอยู่ สำหรับusingมันจะกำจัดวัตถุโดยอัตโนมัติเมื่อสิ้นสุดขอบเขต แต่ไม่ได้ยกเลิกการจัดสรรวัตถุ - อายุการใช้งานจะไม่สิ้นสุดจนกว่าการอ้างอิงทั้งหมดจะหายไป
Joren

1
อาจซ้ำกันของคำหลัก "ใช้" ใน java
HaveNoDisplayName

คำตอบ:


126

Java 7 เปิดตัวAutomatic Resource Block Managementซึ่งนำคุณสมบัตินี้มาสู่แพลตฟอร์ม Java Java เวอร์ชันก่อนหน้าไม่มีอะไรที่คล้ายusingกัน

ตัวอย่างเช่นคุณสามารถใช้ตัวแปรใดก็ได้java.lang.AutoCloseableในการดำเนินการดังต่อไปนี้:

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

java.io.Closeableอินเทอร์เฟซของ Java ที่ใช้งานโดยสตรีมขยายโดยอัตโนมัติAutoCloseableดังนั้นคุณสามารถใช้สตรีมในtryบล็อกแบบเดียวกับที่คุณใช้ในusingบล็อกC # ซึ่งเทียบเท่ากับ C #using's

ในเวอร์ชัน 5.0 ไฮเบอร์เนตเซสชันจะใช้งานAutoCloseableและสามารถปิดอัตโนมัติในบล็อก ARM ในรุ่นก่อนหน้า Hibernate เซสชันไม่ได้ดำเนินการ AutoCloseableดังนั้นคุณจะต้องอยู่ในโหมดไฮเบอร์เนต> = 5.0 เพื่อใช้คุณสมบัตินี้


1
"โชคดี" เมื่อมี Java 7 พร้อมใช้งานแล้วคำตอบนี้ไม่เป็นความจริงอีกต่อไป (และฉันคิดว่าบล็อก ARM คือสิ่งที่usingทำ)
Joachim Sauer

@ Joachim Sauer: ขอบคุณ ฉันอัปเดตคำตอบเพื่อให้สอดคล้องกับกาลเวลา จนถึงจุดที่บล็อก ARM ของคุณเป็นสิ่งที่ใช้ไม่ได้ ในขณะที่ฉันเขียนคำตอบนี้ดูเหมือนว่าฉันจะใช้บล็อก ARM ได้ในขณะที่การใช้งานสามารถนำไปใช้กับบล็อกใดก็ได้ ดูตอนนี้ดูเหมือนว่า do keyword สามารถใช้ใน java เพื่อทำสิ่งนี้ให้สำเร็จได้ มีการเพิ่มข้อเสนอนี้เมื่อเร็ว ๆ นี้หรือฉันพลาดข้อเสนอนี้ในครั้งแรก? นอกจากนี้ OP ยังถามเฉพาะเกี่ยวกับ Hibernate Sessions AFAIK: Hibernate Sessions ยังไม่สามารถใช้งานได้AutoCloseableดังนั้นจึงยังใช้ ARM ไม่ได้
Asaph

1
ไม่ใช่เหตุการณ์ใน 4.3 Hibernate ไม่ใช้ AutoCloseable docs.jboss.org/hibernate/orm/4.3/javadocs/index.html?org/…ฉันเดาว่าทุกคนจะต้องเขียน wrapper ของตัวเอง?
Andrei Rînea

1
เซสชันไม่สามารถใช้ AutoCloseable เป็น Session.close () ส่งคืนการเชื่อมต่อ ฉันคิดว่านี่เป็นการออกแบบที่ไม่ดี แต่ฉันสงสัยว่าสิ่งนี้จะเปลี่ยนแปลงไปตลอดกาล
usr-local-ΕΨΗΕΛΩΝ

@ usr-local-ΕΨΗΕΛΩΝฉันเพิ่งคิดว่าพวกเขาจะต้องบังคับให้ใครก็ตามที่ใช้ hibernate เปลี่ยนไปใช้ java 7 หากพวกเขาใช้อินเทอร์เฟซนั้น AutoCloseableไม่มีมาก่อน java 7 หรือเปล่า?
Neil

31

ก่อน Java 7มีไม่มีคุณสมบัติดังกล่าวในชวา (สำหรับ Java 7 ขึ้นไปดูAsaphคำตอบ 'sเกี่ยวกับARM )

คุณต้องทำด้วยตนเองและมันเป็นความเจ็บปวด :

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

และนี่เป็นเพียงรหัสเมื่อค่า// Great codeมิได้hooray.close()สามารถโยนข้อยกเว้นใด ๆ

หากคุณต้องการ จำกัด ขอบเขตของตัวแปรจริงๆบล็อกโค้ดธรรมดาจะทำงาน:

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

แต่นั่นอาจไม่ใช่สิ่งที่คุณหมายถึง


1
การเทียบเท่า Java ของคุณจะไม่มีปัญหาหาก// Great codeมีข้อยกเว้น
Cheeso

3
เมื่อตัวสร้างแสดงข้อยกเว้นฉันคิดว่าโค้ดของคุณจะส่งผลให้ NullPointerException ปิดบังข้อยกเว้นเดิม
Michael Borgwardt

@ ไมเคิล: จริงๆแล้วตัวอย่างของฉันจะไม่รวบรวมเพราะhorrayอาจไม่ได้เริ่มต้น ณ จุดนั้น (แก้ไขแล้ว)
Joachim Sauer

4
+1 สำหรับบล็อกแบบลอยตัวที่สามารถ จำกัด ขอบเขตได้ อย่างไรก็ตามเมื่อใดก็ตามที่ฉันเห็นสิ่งเหล่านี้มักจะเป็นตัวบ่งชี้ว่าวิธีการนี้ควรแบ่งออกเป็นชิ้นเล็ก ๆ
Mark Peters

1
หากคุณต้องการจับข้อยกเว้นใด ๆ จากตัวสร้างคุณต้องมีมันอยู่ในบล็อกลอง มันจะยุ่งยากในการสรุปสิ่งทั้งหมดด้วยการลอง / จับอีกครั้ง
ths

19

ตั้งแต่ Java 7 มันทำ: http://blogs.oracle.com/darcy/entry/project_coin_updated_arm_spec

ไวยากรณ์ของรหัสในคำถามจะเป็น:

try (Session session = new Session())
{
  // do stuff
}

โปรดทราบว่าSessionจำเป็นต้องใช้AutoClosableหรือหนึ่งในอินเทอร์เฟซย่อย (หลายรายการ)


8

ในทางเทคนิค:

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

2
ไม่ใช่วิธีที่ดีที่สุดที่จะทำ stackoverflow.com/questions/1909662/…
Mark Byers

5
สิ่งนี้จะเทียบเท่ากันเป็นหลัก ฉันไม่สนว่ามันจะเป็นวิธีที่ดีที่สุด
ChaosPandion

2
เขียนเหมือนโปรแกรมเมอร์ C # จริงๆ ;)
นีล

8

เทียบเท่ากับ java ที่ใกล้เคียงที่สุดคือ

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



2

หากคุณสนใจในการจัดการทรัพยากรProject Lombokขอเสนอ@Cleanupคำอธิบายประกอบ ถ่ายโดยตรงจากเว็บไซต์ของพวกเขา:

คุณสามารถใช้@Cleanupเพื่อให้แน่ใจว่าทรัพยากรที่กำหนดจะถูกล้างโดยอัตโนมัติก่อนที่เส้นทางการเรียกใช้โค้ดจะออกจากขอบเขตปัจจุบันของคุณ คุณทำได้โดยใส่คำอธิบายประกอบการประกาศตัวแปรภายในด้วย@Cleanup คำอธิบายประกอบดังนี้:

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

ดังนั้นในตอนท้ายของขอบเขตที่คุณอยู่จะin.close()ถูกเรียกว่า สายนี้รับประกันว่าจะดำเนินการโดยการลอง / สร้างในที่สุด ดูตัวอย่างด้านล่างเพื่อดูวิธีการทำงาน

หากประเภทของออบเจ็กต์ที่คุณต้องการล้างไม่มีclose() เมธอด แต่มีวิธีการอื่นที่ไม่มีอาร์กิวเมนต์คุณสามารถระบุชื่อของเมธอดนี้ได้ดังนี้:

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

close()โดยค่าเริ่มต้นวิธีการทำความสะอาดที่มีการสันนิษฐานว่าเป็น @Cleanupวิธีการทำความสะอาดที่ใช้อาร์กิวเมนต์ไม่สามารถเรียกว่าผ่าน

วานิลลาชวา

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();
    }
  }
}

กับเกาะลอมบอก

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

โปรดดูรายการคีย์เวิร์ด Javaนี้

  1. usingคำหลักที่เป็นที่น่าเสียดายไม่เป็นส่วนหนึ่งของรายการ
  2. และยังไม่มีความเท่าเทียมกันของusingคีย์เวิร์ดC # ผ่านคีย์เวิร์ดอื่น ๆ สำหรับตอนนี้ใน Java

ที่จะเลียนแบบเช่น"using"พฤติกรรมที่คุณจะต้องใช้บล็อกที่คุณจะทิ้งของทรัพยากรภายในtry...catch...finallyfinally


6
ความจริงที่usingไม่ใช่คีย์เวิร์ดไม่ได้หมายถึงสิ่ง คุณลักษณะเดียวกันนี้สามารถนำไปใช้ (และจะ!) ด้วยคำหลักอื่นตามที่ @BalusC กล่าวถึง
Joachim Sauer

1
ฉันเห็นด้วย! แต่ตอนนี้มันไม่มีแล้วใช่มั้ย? นั่นคือสิ่งที่ OP ถามว่าเมื่อกี้นี้มีอะไรเหมือนกันหรือเปล่า เป็นเรื่องดีที่ทราบว่าจะมีอยู่ในรุ่นต่อ ๆ ไป แต่ไม่ได้เปลี่ยนแปลงอะไรในตอนนี้ไม่ทางใดก็ทางหนึ่ง อย่างไรก็ตามข้อมูลที่ให้โดย @BalusC นั้นยอดเยี่ยมมาก! =)
Will Marcouiller

2
ฉันเห็นด้วยกับสิ่งนั้น แต่ดูเหมือนว่าโพสต์ของคุณจะบอกว่าความจริงที่usingไม่อยู่ในรายการคีย์เวิร์ด Java หมายความว่าคุณลักษณะนี้ไม่มีอยู่ในภาษา Java และนั่นไม่เป็นความจริง
Joachim Sauer

หากนี่คือสิ่งที่โพสต์ของฉันดูเหมือนจะพูดฉันจะแก้ไขเพื่อให้สอดคล้องกับความตั้งใจของฉัน
Will Marcouiller

ฉันแก้ไขคำตอบของฉันโดยระบุว่าไม่มีusingคีย์เวิร์ดและไม่มีความเท่าเทียมใด ๆ ในตอนนี้ ขอบคุณ @Joachim Sauer! =)
Will Marcouiller

1

บล็อก ARMจากproject coinจะอยู่ใน Java 7 ซึ่งเป็นคุณลักษณะนี้มีไว้เพื่อนำฟังก์ชันการทำงานที่คล้ายคลึงกับ Java มาใช้เป็น. Net โดยใช้ไวยากรณ์


0

เพื่อตอบคำถามเกี่ยวกับการ จำกัด ขอบเขตของตัวแปรแทนที่จะพูดถึงการปิด / กำจัดตัวแปรโดยอัตโนมัติ

ใน Java คุณสามารถกำหนดขอบเขตแบบปิดและไม่ระบุชื่อโดยใช้วงเล็บปีกกา มันง่ายมาก

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

ตัวแปรhoorayสามารถใช้ได้เฉพาะในขอบเขตนี้และไม่อยู่นอกตัวแปร

สิ่งนี้จะมีประโยชน์หากคุณมีตัวแปรซ้ำซึ่งเป็นเพียงชั่วคราว

ตัวอย่างเช่นแต่ละรายการมีดัชนี เช่นเดียวกับitemตัวแปรที่ปิดอยู่บน for loop (กล่าวคือใช้ได้เฉพาะภายใน) indexตัวแปรจะถูกปิดในขอบเขตที่ไม่ระบุตัวตน

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

ฉันยังใช้สิ่งนี้ในบางครั้งหากคุณไม่มี for loop เพื่อระบุขอบเขตตัวแปร แต่คุณต้องการใช้ชื่อตัวแปรทั่วไป

{
    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);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.