Null check chain เทียบกับการจับ NullPointerException


118

บริการเว็บส่งคืน XML ขนาดใหญ่และฉันต้องการเข้าถึงช่องที่ซ้อนกันอย่างลึกซึ้ง ตัวอย่างเช่น:

return wsObject.getFoo().getBar().getBaz().getInt()

ปัญหาคือว่าgetFoo(), getBar(), อาจกลับมาทั้งหมดgetBaz()null

อย่างไรก็ตามหากฉันตรวจสอบnullในทุกกรณีรหัสจะดูละเอียดมากและอ่านยาก ยิ่งไปกว่านั้นฉันอาจพลาดการตรวจสอบบางฟิลด์

if (wsObject.getFoo() == null) return -1;
if (wsObject.getFoo().getBar() == null) return -1;
// maybe also do something with wsObject.getFoo().getBar()
if (wsObject.getFoo().getBar().getBaz() == null) return -1;
return wsObject.getFoo().getBar().getBaz().getInt();

เป็นที่ยอมรับหรือไม่ที่จะเขียน

try {
    return wsObject.getFoo().getBar().getBaz().getInt();
} catch (NullPointerException ignored) {
    return -1;
}

หรือจะถือว่าเป็นปฏิปักษ์?


29
ฉันจะไม่สนใจการnullตรวจสอบมากนักเนื่องจากwsObject.getFoo().getBar().getBaz().getInt()เป็นกลิ่นรหัสอยู่แล้ว อ่านว่า"Law of Demeter"คืออะไรและต้องการปรับรหัสของคุณให้สอดคล้องกัน แล้วปัญหาเรื่องnullเช็คก็จะหมดไปเช่นกัน และคิดเกี่ยวกับการใช้Optional.
ทอม

9
สิ่งที่เกี่ยวกับการใช้XPathและปล่อยให้การประเมินของพวกเขา?
Joop Eggen

15
รหัสนั้นอาจถูกสร้างขึ้นโดยwsdl2javaที่ไม่เคารพกฎหมายของ Demeter
Adrian Cox

คำตอบ:


143

การจับNullPointerExceptionเป็นปัญหาที่ต้องทำเนื่องจากสามารถเกิดขึ้นได้เกือบทุกที่ มันง่ายมากที่จะรับหนึ่งจากข้อบกพร่องจับมันโดยบังเอิญและดำเนินการต่อราวกับว่าทุกอย่างเป็นปกติดังนั้นจึงซ่อนปัญหาที่แท้จริงไว้ เป็นเรื่องยุ่งยากมากที่จะจัดการดังนั้นจึงควรหลีกเลี่ยงโดยสิ้นเชิง (ตัวอย่างเช่นลองนึกถึงการแกะกล่องว่างIntegerอัตโนมัติ)

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

โดยใช้ว่าคุณสามารถเขียนโค้ดของคุณได้ดังนี้:

public Optional<Integer> m(Ws wsObject) {
    return Optional.ofNullable(wsObject.getFoo()) // Here you get Optional.empty() if the Foo is null
        .map(f -> f.getBar()) // Here you transform the optional or get empty if the Bar is null
        .map(b -> b.getBaz())
        .map(b -> b.getInt());
        // Add this if you want to return null instead of an empty optional if any is null
        // .orElse(null);
        // Or this if you want to throw an exception instead
        // .orElseThrow(SomeApplicationException::new);
}

ทำไมไม่จำเป็น?

การใช้Optionals แทนnullค่าที่อาจไม่มีอยู่ทำให้ผู้อ่านมองเห็นได้ชัดเจนและชัดเจนและระบบประเภทจะช่วยให้แน่ใจว่าคุณจะไม่ลืมมันโดยไม่ได้ตั้งใจ

นอกจากนี้คุณยังได้รับการเข้าถึงวิธีการสำหรับการทำงานที่มีค่าดังกล่าวมากขึ้นสะดวกเหมือนและmaporElse


ไม่มีถูกต้องหรือผิดพลาด?

แต่ให้คิดด้วยว่ามันเป็นผลลัพธ์ที่ถูกต้องสำหรับวิธีการระดับกลางในการคืนค่า null หรือถ้านั่นเป็นสัญญาณของข้อผิดพลาด หากเป็นข้อผิดพลาดเสมอก็น่าจะดีกว่าที่จะส่งกลับค่าพิเศษหรือสำหรับวิธีการขั้นกลางเองที่จะโยนข้อยกเว้น


อาจมีตัวเลือกเพิ่มเติม?

หากในทางกลับกันค่าที่ไม่มีจากวิธีการระดับกลางก็ถูกต้องคุณสามารถเปลี่ยนไปใช้Optionals สำหรับพวกเขาได้หรือไม่?

จากนั้นคุณสามารถใช้มันได้ดังนี้:

public Optional<Integer> mo(Ws wsObject) {
    return wsObject.getFoo()
        .flatMap(f -> f.getBar())
        .flatMap(b -> b.getBaz())
        .flatMap(b -> b.getInt());        
}

ทำไมไม่เลือก?

เหตุผลเดียวที่ฉันคิดได้สำหรับการไม่ใช้Optionalก็คือถ้าสิ่งนี้อยู่ในส่วนที่มีความสำคัญต่อประสิทธิภาพจริงๆของโค้ดและหากค่าใช้จ่ายในการรวบรวมขยะกลายเป็นปัญหา เนื่องจากOptionalมีการจัดสรรออบเจ็กต์สองสามชิ้นในแต่ละครั้งที่มีการเรียกใช้โค้ดและ VM อาจไม่สามารถเพิ่มประสิทธิภาพเหล่านั้นออกไปได้ ในกรณีนี้การทดสอบ if ดั้งเดิมของคุณอาจดีกว่า


ตอบได้ดีมาก. ควรกล่าวถึงว่าหากมีเงื่อนไขความล้มเหลวอื่น ๆ ที่เป็นไปได้และคุณจำเป็นต้องแยกแยะระหว่างสิ่งเหล่านี้คุณสามารถใช้TryแทนOptionalได้ แม้ว่าจะไม่มีTryใน Java API แต่ก็มี libs จำนวนมากที่ให้บริการเช่นjavaslang.io , github.com/bradleyscollins/try4j , functionaljava.orgหรือgithub.com/jasongoodwin/better-java-monads
Landei

8
FClass::getBarฯลฯ จะสั้นกว่า
Boris the Spider

1
@BoristheSpider: อาจจะเล็กน้อย แต่ฉันมักจะชอบ lambdas มากกว่า method refs เพราะบ่อยครั้งชื่อ class จะยาวกว่ามากและฉันพบว่า lambdas อ่านง่ายกว่าเล็กน้อย
Lii

6
@Lii ยุติธรรมเพียงพอ แต่โปรดทราบว่าการอ้างอิงวิธีการอาจเร็วขึ้นเล็กน้อยเนื่องจากแลมบ์ดาอาจต้องใช้โครงสร้างเวลาคอมไพล์ที่ซับซ้อนมากขึ้น แลมด้าจะต้องมีการสร้างstaticวิธีการซึ่งจะมีโทษเล็กน้อยมาก
Boris the Spider

1
@Lii ฉันพบว่าการอ้างอิงวิธีการนั้นดูสะอาดและมีคำอธิบายมากขึ้นแม้ว่าจะยาวกว่าเล็กน้อยก็ตาม
shmosel

14

Objects.requireNonNull(T obj, String message)ผมขอแนะนำให้พิจารณา คุณอาจสร้างเครือข่ายที่มีข้อความโดยละเอียดสำหรับแต่ละข้อยกเว้นเช่น

requireNonNull(requireNonNull(requireNonNull(
    wsObject, "wsObject is null")
        .getFoo(), "getFoo() is null")
            .getBar(), "getBar() is null");

-1ผมขอแนะนำให้คุณที่จะไม่ใช้ผลตอบแทนพิเศษค่าเช่น นั่นไม่ใช่สไตล์ Java Java ได้ออกแบบกลไกของข้อยกเว้นเพื่อหลีกเลี่ยงวิธีที่ล้าสมัยซึ่งมาจากภาษา C

การขว้างปาNullPointerExceptionไม่ใช่ตัวเลือกที่ดีที่สุดเช่นกัน คุณสามารถระบุข้อยกเว้นของคุณเองได้ (ทำการตรวจสอบเพื่อรับประกันว่าผู้ใช้จะจัดการหรือยกเลิกการเลือกเพื่อประมวลผลด้วยวิธีที่ง่ายกว่า) หรือใช้ข้อยกเว้นเฉพาะจากตัวแยกวิเคราะห์ XML ที่คุณใช้


1
Objects.requireNonNullNullPointerExceptionในที่สุดก็โยน ดังนั้นนี่จึงไม่ทำให้สถานการณ์แตกต่างไปจากreturn wsObject.getFoo().getBar().getBaz().getInt()
Arka Ghosh

1
@ArkaGhosh นอกจากนี้ยังหลีกเลี่ยงสิ่งต่างๆมากมายifตามที่ OP แสดง
Andrew Tobilko

4
นี่เป็นทางออกเดียวที่ดี คนอื่น ๆ ทั้งหมดแนะนำให้ใช้ข้อยกเว้นสำหรับการควบคุมการไหลซึ่งเป็นกลิ่นรหัส หมายเหตุด้านข้าง: ฉันพิจารณาวิธีการผูกมัดโดย OP ด้วยกลิ่นเช่นกัน ถ้าเขาจะทำงานกับตัวแปรท้องถิ่นสามตัวและสถานการณ์ของ if ที่สอดคล้องกันจะชัดเจนกว่ามาก นอกจากนี้ฉันคิดว่าปัญหานั้นลึกกว่าแค่การทำงานกับ NPE: OP ควรถามตัวเองว่าทำไม getters ถึงคืนค่าว่างได้ null หมายถึงอะไร? บางทีวัตถุว่างจะดีกว่าไหม หรือผิดพลาดในหนึ่ง getter โดยมีข้อยกเว้นที่มีความหมาย? โดยพื้นฐานแล้วทุกอย่างดีกว่าข้อยกเว้นสำหรับการควบคุมการไหล
Marius K.

1
คำแนะนำที่ไม่มีเงื่อนไขในการใช้ข้อยกเว้นเพื่อส่งสัญญาณว่าไม่มีค่าส่งคืนที่ถูกต้องนั้นไม่ค่อยดีนัก ข้อยกเว้นมีประโยชน์เมื่อเมธอดล้มเหลวในลักษณะที่ยากสำหรับผู้เรียกที่จะกู้คืนและจัดการได้ดีกว่าในคำสั่ง try-catch-ในส่วนอื่น ๆ ของโปรแกรม หากต้องการเพียงแค่ส่งสัญญาณว่าไม่มีค่าส่งคืนจะเป็นการดีกว่าที่จะใช้Optionalคลาสหรืออาจส่งคืนค่าว่างInteger
Lii

6

สมมติว่าโครงสร้างชั้นเรียนอยู่นอกการควบคุมของเราอย่างที่เป็นอยู่ฉันคิดว่าการจับ NPE ตามที่แนะนำในคำถามนั้นเป็นวิธีแก้ปัญหาที่สมเหตุสมผลเว้นแต่ประสิทธิภาพจะเป็นปัญหาหลัก การปรับปรุงเล็กน้อยอย่างหนึ่งอาจเป็นการรวมตรรกะการโยน / จับเพื่อหลีกเลี่ยงความยุ่งเหยิง:

static <T> T get(Supplier<T> supplier, T defaultValue) {
    try {
        return supplier.get();
    } catch (NullPointerException e) {
        return defaultValue;
    }
}

ตอนนี้คุณสามารถทำได้:

return get(() -> wsObject.getFoo().getBar().getBaz().getInt(), -1);

return get(() -> wsObject.getFoo().getBar().getBaz().getInt(), "");ไม่ให้ข้อผิดพลาดในเวลาคอมไพล์ซึ่งอาจเป็นปัญหาได้
Philippe Gioseffi

5

ดังที่ทอมได้ชี้ให้เห็นแล้วในความคิดเห็น

ต่อไปนี้ไม่เชื่อฟังคำสั่งกฎหมายของ Demeter ,

wsObject.getFoo().getBar().getBaz().getInt()

สิ่งที่คุณต้องการเป็นและคุณจะได้รับจากint กฎหมายของ Demeterกล่าวว่าไม่เคยพูดคุยกับคนแปลกหน้า สำหรับกรณีของคุณคุณสามารถซ่อนการปฏิบัติจริงภายใต้ประทุนของและFooFooBar

ตอนนี้คุณสามารถสร้างวิธีการในการFooดึงข้อมูลจากint Bazในท้ายที่สุดFooจะมีBarและBarเราสามารถเข้าถึงIntโดยไม่ต้องเปิดเผยตรงไปยังBaz Fooดังนั้นการตรวจสอบค่าว่างอาจแบ่งออกเป็นคลาสต่างๆและจะมีการแชร์เฉพาะแอตทริบิวต์ที่จำเป็นระหว่างคลาส


4
เป็นที่ถกเถียงกันอยู่ว่ามันฝ่าฝืน Law Of Demeter เนื่องจาก WsObject อาจเป็นเพียงโครงสร้างข้อมูล ดูที่นี่: stackoverflow.com/a/26021695/1528880
DerM

2
@DerM ใช่เป็นไปได้ แต่เนื่องจาก OP มีบางอย่างที่แยกวิเคราะห์ไฟล์ XML ของเขาอยู่แล้วเขายังสามารถคิดเกี่ยวกับการสร้างคลาสโมเดลที่เหมาะสมสำหรับแท็กที่ต้องการเพื่อให้ไลบรารีแยกวิเคราะห์สามารถแมปได้ จากนั้นคลาสโมเดลเหล่านี้จะมีตรรกะสำหรับการnullตรวจสอบแท็กย่อยของตัวเอง
ทอม

4

คำตอบของฉันเกือบจะอยู่ในบรรทัดเดียวกับ @janki แต่ฉันต้องการแก้ไขข้อมูลโค้ดเล็กน้อยดังนี้:

if (wsObject.getFoo() != null && wsObject.getFoo().getBar() != null && wsObject.getFoo().getBar().getBaz() != null) 
   return wsObject.getFoo().getBar().getBaz().getInt();
else
   return something or throw exception;

คุณสามารถเพิ่มการตรวจสอบค่าว่างได้wsObjectเช่นกันหากมีโอกาสที่วัตถุนั้นจะเป็นโมฆะ


4

คุณบอกว่าวิธีการบางอย่าง "อาจกลับมาnull" แต่ไม่ได้บอกว่ามันกลับมาในกรณีnullใด คุณบอกว่าคุณจับได้NullPointerExceptionแต่คุณไม่ได้บอกว่าคุณจับทำไม การขาดข้อมูลนี้แสดงให้เห็นว่าคุณไม่มีความเข้าใจอย่างชัดเจนว่ามีข้อยกเว้นอะไรบ้างและเหตุใดจึงเหนือกว่าทางเลือกอื่น

พิจารณาวิธีการคลาสที่มีไว้เพื่อดำเนินการ แต่เมธอดไม่สามารถรับประกันได้ว่าจะดำเนินการดังกล่าวเนื่องจากสถานการณ์ที่อยู่นอกเหนือการควบคุม (ซึ่งในความเป็นจริงเป็นกรณีของวิธีการทั้งหมดใน Java ) เราเรียกวิธีนั้นแล้วมันจะส่งกลับ รหัสที่เรียกเมธอดนั้นจำเป็นต้องทราบว่าสำเร็จหรือไม่ มันรู้ได้ยังไง? จะมีโครงสร้างเพื่อรับมือกับความเป็นไปได้ทั้งสองความสำเร็จหรือความล้มเหลวได้อย่างไร?

การใช้ข้อยกเว้นเราสามารถเขียนวิธีการที่มีความสำเร็จเป็นเงื่อนไขที่โพสต์ หากวิธีการคืนค่าแสดงว่าสำเร็จ หากมีข้อยกเว้นแสดงว่าล้มเหลว นี่คือชัยชนะครั้งใหญ่สำหรับความชัดเจน เราสามารถเขียนโค้ดที่ประมวลผลกรณีปกติกรณีสำเร็จอย่างชัดเจนและย้ายโค้ดการจัดการข้อผิดพลาดทั้งหมดไปไว้ในcatchประโยค มักจะปรากฏว่ารายละเอียดของวิธีการหรือสาเหตุที่วิธีการไม่ประสบความสำเร็จนั้นไม่สำคัญสำหรับผู้เรียกดังนั้นจึงcatchสามารถใช้ประโยคเดียวกันเพื่อจัดการกับความล้มเหลวหลายประเภทได้ และมันมักจะเกิดขึ้นว่าวิธีการที่ไม่จำเป็นต้องมีข้อยกเว้นที่จับได้ทั้งหมดแต่ก็สามารถช่วยให้พวกเขาเพื่อเผยแพร่สู่ของผู้โทร ข้อยกเว้นเนื่องจากข้อบกพร่องของโปรแกรมอยู่ในระดับหลังนั้น ไม่กี่วิธีที่สามารถตอบสนองได้อย่างเหมาะสมเมื่อมีข้อบกพร่อง

nullดังนั้นวิธีการเหล่านั้นว่าการกลับมา

  • ที่ไม่nullคุ้มค่าบ่งชี้ถึงข้อผิดพลาดในรหัสของคุณหรือไม่? หากเป็นเช่นนั้นคุณไม่ควรจับข้อยกเว้นเลย และรหัสของคุณไม่ควรพยายามเดาซ้ำสอง เพียงเขียนสิ่งที่ชัดเจนและรัดกุมบนสมมติฐานที่จะใช้งานได้ ห่วงโซ่ของวิธีการเรียกที่ชัดเจนและรัดกุมหรือไม่? จากนั้นก็ใช้มัน
  • ที่ไม่nullคุ้มค่าบ่งชี้ถึงการป้อนข้อมูลที่ไม่ถูกต้องในการเขียนโปรแกรมของคุณหรือไม่ ถ้าเป็นเช่นนั้น a NullPointerExceptionไม่ใช่ข้อยกเว้นที่เหมาะสมในการโยนเนื่องจากตามอัตภาพถูกสงวนไว้สำหรับระบุข้อบกพร่อง คุณอาจต้องการโยนข้อยกเว้นแบบกำหนดเองที่ได้มาจากIllegalArgumentException(หากคุณต้องการข้อยกเว้นที่ไม่ได้เลือกไว้ ) หรือIOException(หากคุณต้องการให้มีการตรวจสอบข้อยกเว้น) โปรแกรมของคุณจำเป็นต้องระบุข้อความแสดงข้อผิดพลาดทางไวยากรณ์โดยละเอียดหรือไม่เมื่อมีการป้อนข้อมูลที่ไม่ถูกต้อง? หากเป็นเช่นนั้นการตรวจสอบแต่ละวิธีเพื่อหาnullค่าที่ส่งคืนจากนั้นจึงทิ้งข้อยกเว้นการวินิจฉัยที่เหมาะสมเป็นสิ่งเดียวที่คุณทำได้ หากโปรแกรมของคุณไม่จำเป็นต้องให้การวินิจฉัยโดยละเอียดการผูกมัดการเรียกเมธอดเข้าด้วยกันการจับNullPointerExceptionข้อยกเว้นที่กำหนดเองของคุณแล้วโยนออกไปนั้นชัดเจนและรัดกุมที่สุด

หนึ่งในคำตอบอ้างว่าวิธีการที่ถูกล่ามโซ่นั้นละเมิดกฎของ Demeterจึงไม่ดี คำกล่าวอ้างนั้นผิดพลาด

  • เมื่อพูดถึงการออกแบบโปรแกรมไม่มีกฎเกณฑ์ที่แน่นอนเกี่ยวกับสิ่งที่ดีและสิ่งที่ไม่ดี มีเพียงการวิเคราะห์พฤติกรรมเท่านั้น: กฎที่ถูกต้องมาก (แม้เกือบทั้งหมด) ของเวลา ทักษะในการเขียนโปรแกรมส่วนหนึ่งคือการรู้ว่าเมื่อใดที่สามารถฝ่าฝืนกฎประเภทนั้นได้ ดังนั้นการยืนยันอย่างสั้น ๆ ว่า "สิ่งนี้ผิดกฎX " จึงไม่ใช่คำตอบที่แท้จริง นี่เป็นหนึ่งในสถานการณ์ที่ควรทำลายกฎหรือไม่?
  • กฎหมายของ Demeterมันเป็นกฎเกี่ยวกับ API หรืออินเตอร์เฟซที่ออกแบบชั้น เมื่อออกแบบชั้นเรียนการมีลำดับชั้นของนามธรรมจะเป็นประโยชน์. คุณมีคลาสระดับต่ำที่ใช้พื้นฐานของภาษาเพื่อดำเนินการโดยตรงและแสดงอ็อบเจ็กต์ในสิ่งที่เป็นนามธรรมที่อยู่ในระดับที่สูงกว่าพื้นฐานของภาษา คุณมีคลาสระดับกลางที่มอบสิทธิ์ให้กับคลาสระดับต่ำและใช้การดำเนินการและการเป็นตัวแทนในระดับที่สูงกว่าคลาสระดับต่ำ คุณมีคลาสระดับสูงที่มอบสิทธิ์ให้กับคลาสระดับกลางและใช้การดำเนินการในระดับที่สูงกว่าและนามธรรม (ฉันได้พูดถึงนามธรรมเพียงสามระดับที่นี่ แต่เป็นไปได้มากกว่านั้น) สิ่งนี้ช่วยให้โค้ดของคุณแสดงตัวตนในแง่ของนามธรรมที่เหมาะสมในแต่ละระดับซึ่งจะซ่อนความซับซ้อนไว้ เหตุผลของกฎหมาย Demeterคือถ้าคุณมีการเรียกใช้วิธีการแบบโซ่นั่นแสดงว่าคุณมีคลาสระดับสูงที่เข้าถึงผ่านคลาสระดับกลางเพื่อจัดการโดยตรงกับรายละเอียดระดับต่ำดังนั้นคลาสระดับกลางของคุณไม่ได้ให้การดำเนินการนามธรรมระดับกลาง ที่คนระดับสูงต้องการ แต่ดูเหมือนว่าจะไม่ใช่สถานการณ์ที่คุณมีอยู่ที่นี่: คุณไม่ได้ออกแบบคลาสในเชนของการเรียกเมธอดซึ่งเป็นผลมาจากโค้ดซีเรียลไลเซชัน XML ที่สร้างขึ้นโดยอัตโนมัติ (ใช่ไหม) และสายการโทรไม่ได้ลดลง ผ่านลำดับชั้นที่เป็นนามธรรมเนื่องจาก XML ที่จัดลำดับตามลำดับทั้งหมดอยู่ในระดับเดียวกันของลำดับชั้นที่เป็นนามธรรม (ใช่ไหม)?

3

เพื่อปรับปรุงความสามารถในการอ่านคุณอาจต้องการใช้ตัวแปรหลายตัวเช่น

Foo theFoo;
Bar theBar;
Baz theBaz;

theFoo = wsObject.getFoo();

if ( theFoo == null ) {
  // Exit.
}

theBar = theFoo.getBar();

if ( theBar == null ) {
  // Exit.
}

theBaz = theBar.getBaz();

if ( theBaz == null ) {
  // Exit.
}

return theBaz.getInt();

สิ่งนี้อ่านได้น้อยมากในความคิดของฉัน มันทิ้งวิธีการด้วยตรรกะการตรวจสอบค่าว่างทั้งหมดซึ่งไม่เกี่ยวข้องกับตรรกะที่แท้จริงของวิธีการ
พัฒนา

2

อย่าจับNullPointerException. คุณไม่รู้ว่ามันมาจากไหน (ฉันรู้ว่ามันไม่น่าจะเป็นไปได้ในกรณีของคุณ แต่อาจมีอย่างอื่นโยนทิ้ง) และมันก็ช้า คุณต้องการเข้าถึงฟิลด์ที่ระบุและฟิลด์อื่น ๆ ทั้งหมดจะต้องไม่เป็นโมฆะ นี่เป็นเหตุผลที่ถูกต้องสมบูรณ์ในการตรวจสอบทุกฟิลด์ ฉันอาจจะตรวจสอบในหนึ่งถ้าแล้วสร้างวิธีการสำหรับการอ่าน ตามที่คนอื่น ๆ ชี้ให้เห็นแล้วว่าการกลับมา -1 นั้นเก่ามาก แต่ฉันไม่รู้ว่าคุณมีเหตุผลหรือไม่ (เช่นคุยกับระบบอื่น)

public int callService() {
    ...
    if(isValid(wsObject)){
        return wsObject.getFoo().getBar().getBaz().getInt();
    }
    return -1;
}


public boolean isValid(WsObject wsObject) {
    if(wsObject.getFoo() != null &&
        wsObject.getFoo().getBar() != null &&
        wsObject.getFoo().getBar().getBaz() != null) {
        return true;
    }
    return false;
}

แก้ไข: เป็นที่ถกเถียงกันอยู่ว่ามันฝ่าฝืน Law Of Demeter เนื่องจาก WsObject อาจเป็นเพียงโครงสร้างข้อมูล (ตรวจสอบhttps://stackoverflow.com/a/26021695/1528880 )


2

หากคุณไม่ต้องการ refactor โค้ดและคุณสามารถใช้ Java 8 ได้คุณสามารถใช้การอ้างอิง Method ได้

การสาธิตอย่างง่ายก่อน (ขออภัยคลาสภายในคงที่)

public class JavaApplication14 
{
    static class Baz
    {
        private final int _int;
        public Baz(int value){ _int = value; }
        public int getInt(){ return _int; }
    }
    static class Bar
    {
        private final Baz _baz;
        public Bar(Baz baz){ _baz = baz; }
        public Baz getBar(){ return _baz; }   
    }
    static class Foo
    {
        private final Bar _bar;
        public Foo(Bar bar){ _bar = bar; }
        public Bar getBar(){ return _bar; }   
    }
    static class WSObject
    {
        private final Foo _foo;
        public WSObject(Foo foo){ _foo = foo; }
        public Foo getFoo(){ return _foo; }
    }
    interface Getter<T, R>
    {
        R get(T value);
    }

    static class GetterResult<R>
    {
        public R result;
        public int lastIndex;
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) 
    {
        WSObject wsObject = new WSObject(new Foo(new Bar(new Baz(241))));
        WSObject wsObjectNull = new WSObject(new Foo(null));

        GetterResult<Integer> intResult
                = getterChain(wsObject, WSObject::getFoo, Foo::getBar, Bar::getBar, Baz::getInt);

        GetterResult<Integer> intResult2
                = getterChain(wsObjectNull, WSObject::getFoo, Foo::getBar, Bar::getBar, Baz::getInt);


        System.out.println(intResult.result);
        System.out.println(intResult.lastIndex);

        System.out.println();
        System.out.println(intResult2.result);
        System.out.println(intResult2.lastIndex);

        // TODO code application logic here
    }

    public static <R, V1, V2, V3, V4> GetterResult<R>
            getterChain(V1 value, Getter<V1, V2> g1, Getter<V2, V3> g2, Getter<V3, V4> g3, Getter<V4, R> g4)
            {
                GetterResult result = new GetterResult<>();

                Object tmp = value;


                if (tmp == null)
                    return result;
                tmp = g1.get((V1)tmp);
                result.lastIndex++;


                if (tmp == null)
                    return result;
                tmp = g2.get((V2)tmp);
                result.lastIndex++;

                if (tmp == null)
                    return result;
                tmp = g3.get((V3)tmp);
                result.lastIndex++;

                if (tmp == null)
                    return result;
                tmp = g4.get((V4)tmp);
                result.lastIndex++;


                result.result = (R)tmp;

                return result;
            }
}

เอาท์พุต

241
4

null
2

อินเทอร์เฟซGetterเป็นเพียงอินเทอร์เฟซที่ใช้งานได้คุณสามารถใช้สิ่งที่เทียบเท่าได้
GetterResultclass, accessors ถอดออกเพื่อความชัดเจน, ถือผลลัพธ์ของ getter chain, ถ้ามี, หรือดัชนีของ getter ล่าสุดที่เรียก

วิธีการgetterChainนี้เป็นโค้ดที่เรียบง่ายซึ่งสามารถสร้างขึ้นโดยอัตโนมัติ (หรือด้วยตนเองเมื่อจำเป็น)
ฉันจัดโครงสร้างโค้ดเพื่อให้บล็อกการทำซ้ำนั้นชัดเจนในตัวเอง


นี่ไม่ใช่วิธีแก้ปัญหาที่สมบูรณ์แบบเนื่องจากคุณยังต้องกำหนดหนึ่งโอเวอร์โหลดgetterChainต่อจำนวนผู้ได้รับ

ฉันจะ refactor รหัสแทน แต่ถ้าทำไม่ได้และคุณพบว่าตัวเองใช้โซ่ยาว ๆ บ่อยครั้งคุณอาจพิจารณาสร้างคลาสที่มีโอเวอร์โหลดซึ่งใช้เวลาตั้งแต่ 2 ถึง 10 ขึ้นไป


2

ตามที่คนอื่น ๆ กล่าวการเคารพกฎแห่ง Demeter เป็นส่วนหนึ่งของการแก้ปัญหาอย่างแน่นอน อีกส่วนหนึ่งที่เป็นไปได้คือการเปลี่ยนวิธีการถูกล่ามโซ่เพื่อไม่ให้กลับมาnullอีก คุณสามารถหลีกเลี่ยงกลับnullโดยแทนที่จะกลับมาที่ว่างเปล่าString, ที่ว่างเปล่าCollectionหรือวัตถุบางหุ่นอื่น ๆ nullที่หมายหรือไม่สิ่งที่ผู้โทรจะทำอย่างไรกับ


2

ฉันต้องการที่จะเพิ่มคำตอบซึ่งมุ่งเน้นไปที่ความหมายของข้อผิดพลาด ข้อยกเว้น Null ในตัวเองไม่ได้ให้ข้อผิดพลาดทั้งหมด ดังนั้นฉันขอแนะนำให้หลีกเลี่ยงการติดต่อกับพวกเขาโดยตรง

มีหลายพันกรณีที่รหัสของคุณผิดพลาด: ไม่สามารถเชื่อมต่อกับฐานข้อมูล, ข้อยกเว้น IO, ข้อผิดพลาดของเครือข่าย ... หากคุณจัดการกับพวกเขาทีละรายการ (เช่นการตรวจสอบค่าว่างที่นี่) มันจะเป็นเรื่องยุ่งยากมากเกินไป

ในรหัส:

wsObject.getFoo().getBar().getBaz().getInt();

แม้ว่าคุณจะรู้ว่าฟิลด์ใดเป็นโมฆะคุณก็ไม่รู้ว่าเกิดอะไรขึ้น บางที Bar เป็นโมฆะ แต่คาดว่าจะเป็นอย่างไร หรือเป็นข้อมูลผิดพลาดหรือไม่ นึกถึงคนที่อ่านโค้ดของคุณ

เช่นเดียวกับในคำตอบ xenteros ผมต้องการนำเสนอโดยใช้ข้อยกเว้นที่กำหนดเองไม่ได้ตรวจสอบ ตัวอย่างเช่นในสถานการณ์นี้ Foo สามารถเป็นโมฆะ (ข้อมูลที่ถูกต้อง) แต่ Bar และ Baz ไม่ควรเป็นโมฆะ (ข้อมูลที่ไม่ถูกต้อง)

สามารถเขียนโค้ดใหม่ได้:

void myFunction()
{
    try 
    {
        if (wsObject.getFoo() == null)
        {
          throw new FooNotExistException();
        }

        return wsObject.getFoo().getBar().getBaz().getInt();
    }
    catch (Exception ex)
    {
        log.error(ex.Message, ex); // Write log to track whatever exception happening
        throw new OperationFailedException("The requested operation failed")
    }
}


void Main()
{
    try
    {
        myFunction();
    }
    catch(FooNotExistException)
    {
        // Show error: "Your foo does not exist, please check"
    }
    catch(OperationFailedException)
    {
        // Show error: "Operation failed, please contact our support"
    }
}

ข้อยกเว้นที่ไม่ได้เลือกระบุว่าโปรแกรมเมอร์ใช้ API ในทางที่ผิด ปัญหาภายนอกเช่น "ไม่สามารถเชื่อมต่อกับฐานข้อมูล, ข้อยกเว้น IO, ข้อผิดพลาดของเครือข่าย" ควรระบุด้วยข้อยกเว้นที่ตรวจสอบ
Kevin Krumwiede

มันขึ้นอยู่กับความต้องการของผู้โทรจริงๆ ตรวจสอบข้อยกเว้นช่วยเนื่องจากบังคับให้คุณประมวลผลข้อผิดพลาด อย่างไรก็ตามในกรณีอื่น ๆ ก็ไม่จำเป็นและอาจก่อให้เกิดมลพิษต่อรหัสได้ ตัวอย่างเช่นคุณมี IOException ในชั้นข้อมูลของคุณคุณจะส่งไปที่เลเยอร์การนำเสนอหรือไม่? นั่นหมายความว่าคุณต้องจับข้อยกเว้นและโยนใหม่ให้กับผู้โทรทุกคน ฉันต้องการห่อ IOException ด้วย BusinessException ที่กำหนดเองด้วยข้อความที่เกี่ยวข้องและปล่อยให้ปรากฏผ่าน stacktrace จนกว่าตัวกรองส่วนกลางจะตรวจจับและแสดงข้อความให้ผู้ใช้เห็น
Hoàng Long

ผู้โทรไม่จำเป็นต้องจับและโยนข้อยกเว้นที่ตรวจสอบซ้ำเพียงแค่ประกาศว่าจะถูกโยน
Kevin Krumwiede

@KevinKrumwiede: คุณถูกต้องเราจำเป็นต้องประกาศข้อยกเว้นที่จะถูกโยนเท่านั้น เรายังคงต้องประกาศว่า แก้ไข: เมื่อพิจารณาดูครั้งที่ 2 มีข้อถกเถียงมากมายเกี่ยวกับการใช้ข้อยกเว้นที่ตรวจสอบและไม่ได้ตรวจสอบ (เช่น: programmers.stackexchange.com/questions/121328/… )
Hoàng Long

2

NullPointerException เป็นข้อยกเว้นเวลาทำงานดังนั้นโดยทั่วไปไม่แนะนำให้จับมัน แต่เพื่อหลีกเลี่ยง

คุณจะต้องจับข้อยกเว้นทุกที่ที่คุณต้องการเรียกใช้เมธอด (หรือมันจะแพร่กระจายไปยังสแต็ก) อย่างไรก็ตามหากในกรณีของคุณคุณสามารถทำงานกับผลลัพธ์นั้นต่อไปด้วยค่า -1 และคุณมั่นใจว่าจะไม่แพร่กระจายเนื่องจากคุณไม่ได้ใช้ "ชิ้นส่วน" ใด ๆ ที่อาจเป็นโมฆะฉันจึงคิดว่าถูกต้อง จับมัน

แก้ไข:

ฉันเห็นด้วยกับคำตอบในภายหลังจาก @xenteros จะเป็นการดีกว่าที่จะเปิดข้อยกเว้นของคุณเองแทนที่จะส่งคืน -1 ซึ่งคุณสามารถเรียกได้InvalidXMLExceptionเช่น


3
คุณหมายถึงอะไรกับ "ไม่ว่าคุณจะจับได้ แต่ก็สามารถเผยแพร่ไปยังส่วนอื่น ๆ ของโค้ดได้"
Hulk

ถ้า null อยู่ในประโยคนี้ wsObject.getFoo () และในส่วนต่อมาของโค้ดคุณเรียกใช้คิวรีนั้นอีกครั้งหรือใช้ wsObject.getFoo () getBar () (เช่น) มันจะเพิ่ม NullPointerException อีกครั้ง
SCouto

นั่นเป็นคำที่ผิดปกติสำหรับ "คุณจะต้องจับข้อยกเว้นทุกที่ที่คุณต้องการเรียกใช้เมธอด (หรือมันจะแพร่กระจายไปยังสแต็ก)" ถ้าฉันเข้าใจถูกต้อง ฉันเห็นด้วยกับสิ่งนั้น (และนั่นอาจเป็นปัญหา) ฉันพบว่าถ้อยคำนั้นสับสน
Hulk

ฉันจะแก้ไขขอโทษภาษาอังกฤษไม่ใช่ภาษาแรกของฉันดังนั้นสิ่งนี้อาจเกิดขึ้นในบางครั้ง :) ขอบคุณ
SCouto

2

ติดตามกระทู้นี้มาตั้งแต่เมื่อวานแล้ว

ฉันแสดงความคิดเห็น / โหวตความคิดเห็นที่ระบุว่าการจับ NPE นั้นไม่ดี นี่คือสาเหตุที่ฉันทำอย่างนั้น

package com.todelete;

public class Test {
    public static void main(String[] args) {
        Address address = new Address();
        address.setSomeCrap(null);
        Person person = new Person();
        person.setAddress(address);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            try {
                System.out.println(person.getAddress().getSomeCrap().getCrap());
            } catch (NullPointerException npe) {

            }
        }
        long endTime = System.currentTimeMillis();
        System.out.println((endTime - startTime) / 1000F);
        long startTime1 = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            if (person != null) {
                Address address1 = person.getAddress();
                if (address1 != null) {
                    SomeCrap someCrap2 = address1.getSomeCrap();
                    if (someCrap2 != null) {
                        System.out.println(someCrap2.getCrap());
                    }
                }
            }
        }
        long endTime1 = System.currentTimeMillis();
        System.out.println((endTime1 - startTime1) / 1000F);
    }
}

  public class Person {
    private Address address;

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

package com.todelete;

public class Address {
    private SomeCrap someCrap;

    public SomeCrap getSomeCrap() {
        return someCrap;
    }

    public void setSomeCrap(SomeCrap someCrap) {
        this.someCrap = someCrap;
    }
}

package com.todelete;

public class SomeCrap {
    private String crap;

    public String getCrap() {
        return crap;
    }

    public void setCrap(String crap) {
        this.crap = crap;
    }
}

เอาท์พุต

3.216

0.002

ฉันเห็นผู้ชนะที่ชัดเจนที่นี่ การตรวจสอบมีค่าใช้จ่ายน้อยกว่าการตรวจสอบข้อยกเว้นหรือไม่ ฉันได้เห็นวิธีการทำ Java-8 แล้ว เมื่อพิจารณาว่า 70% ของแอปพลิเคชันปัจจุบันยังคงทำงานบน Java-7 ฉันกำลังเพิ่มคำตอบนี้

Bottom Lineสำหรับแอปพลิเคชันที่สำคัญในภารกิจใด ๆ การจัดการ NPE นั้นมีค่าใช้จ่ายสูง


สามวินาทีพิเศษสำหรับหนึ่งล้านคำขอในกรณีที่เลวร้ายที่สุดนั้นสามารถวัดได้ แต่แทบจะไม่เป็นตัวทำลายข้อตกลงแม้แต่ใน "แอปพลิเคชันที่สำคัญของภารกิจ" มีระบบที่การเพิ่ม 3.2 ไมโครวินาทีในคำขอเป็นเรื่องใหญ่และหากคุณมีระบบดังกล่าวให้พิจารณาข้อยกเว้นอย่างรอบคอบ แต่การเรียกใช้บริการเว็บและการกำหนดค่าเอาต์พุตตามคำถามเดิมอาจใช้เวลานานกว่านั้นมากและกังวลเกี่ยวกับประสิทธิภาพของการจัดการข้อยกเว้นอยู่ข้างจุดนั้น
Jeroen Mostert

@JeroenMostert: 3 วินาทีต่อการตรวจสอบ / ล้าน ดังนั้นจำนวนการตรวจสอบจะเพิ่มต้นทุน
NewUser

จริง แม้ว่าจะเป็นเช่นนั้นฉันก็ยังถือว่าเป็นกรณีของ "โปรไฟล์ก่อน" คุณต้องตรวจสอบมากกว่า 300 ครั้งในหนึ่งคำขอก่อนที่คำขอจะใช้เวลาเพิ่มอีกไม่เกินมิลลิวินาที การพิจารณาการออกแบบจะส่งผลกระทบต่อจิตวิญญาณของฉันเร็วกว่านั้น
Jeroen Mostert

@JeroenMostert: :) เห็นด้วย! ฉันอยากจะฝากไว้กับโปรแกรมเมอร์พร้อมกับผลลัพธ์และให้พวกเขารับสาย!
NewUser

1

หากประสิทธิภาพเป็นปัญหาควรพิจารณาตัวเลือก "จับ" หาก 'จับ' ไม่สามารถนำมาใช้เพราะมันจะเผยแพร่ (ดังกล่าวโดย 'SCouto') จากนั้นใช้ตัวแปรท้องถิ่นเพื่อหลีกเลี่ยงการโทรหลายวิธีgetFoo(), และgetBar()getBaz()


1

ควรพิจารณาเพื่อสร้างข้อยกเว้นของคุณเอง เรียกว่า MyOperationFailedException คุณสามารถโยนมันแทนการคืนค่า ผลลัพธ์จะเหมือนกัน - คุณจะออกจากฟังก์ชัน แต่คุณจะไม่ส่งคืนค่าฮาร์ดโค้ด -1 ซึ่งเป็นรูปแบบการต่อต้าน Java ใน Java เราใช้ข้อยกเว้น

try {
    return wsObject.getFoo().getBar().getBaz().getInt();
} catch (NullPointerException ignored) {
    throw new MyOperationFailedException();
}

แก้ไข:

ตามการอภิปรายในความคิดเห็นให้ฉันเพิ่มบางอย่างในความคิดก่อนหน้านี้ ในรหัสนี้มีความเป็นไปได้สองประการ อย่างหนึ่งคือคุณยอมรับค่าว่างและอีกข้อหนึ่งคือมันเป็นข้อผิดพลาด

หากเป็นข้อผิดพลาดและเกิดขึ้นคุณสามารถดีบักโค้ดของคุณโดยใช้โครงสร้างอื่นเพื่อจุดประสงค์ในการดีบักเมื่อจุดพักไม่เพียงพอ

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


2
คุณไม่คิดว่าเป็นความคิดที่ดีที่จะระงับข้อยกเว้นหรือไม่? ในแบบเรียลไทม์หากเราสูญเสียร่องรอยของข้อยกเว้นความเจ็บปวดที่แท้จริงในด้านล่างเพื่อค้นหาว่าเกิดอะไรขึ้น! ฉันมักจะแนะนำว่าอย่าใช้การผูกมัด ปัญหาที่สองที่ฉันเห็นคือ: รหัสนี้ไม่สามารถให้ผู้รับได้ ณ เวลาหนึ่งซึ่งผลลัพธ์เป็นโมฆะ
NewUser

ไม่ข้อยกเว้นของคุณอาจมีข้อความที่จะชี้สถานที่ที่ถูกโยนทิ้งไป ฉันยอมรับว่าการผูกมัดไม่ใช่ทางออกที่ดีที่สุด :)
xenteros

3
ไม่มันจะพูดเกี่ยวกับหมายเลขบรรทัด ดังนั้นการโทรใด ๆ ในเครือข่ายอาจนำไปสู่ข้อยกเว้น
NewUser

"หากเป็นข้อผิดพลาดและเกิดขึ้นคุณสามารถดีบักโค้ดของคุณ" - ไม่ได้อยู่ในการผลิต ฉันอยากจะรู้มากว่าสิ่งที่ล้มเหลวเมื่อสิ่งที่ฉันมีคือบันทึกแทนที่จะพยายามบอกว่าเกิดอะไรขึ้นเพื่อให้มันล้มเหลว ด้วยคำแนะนำนั้น (และรหัสนั้น) สิ่งที่คุณรู้จริงๆคือหนึ่งใน 4 สิ่งนั้นเป็นโมฆะ แต่ไม่ใช่สิ่งใดหรือเพราะเหตุใด
VLAZ

1

วิธีที่คุณมีนั้นยาว แต่น่าอ่านมาก หากฉันเป็นนักพัฒนารายใหม่ที่เข้ามาในฐานรหัสของคุณฉันจะเห็นว่าคุณทำอะไรได้เร็วพอสมควร คำตอบอื่น ๆ ส่วนใหญ่ (รวมถึงการจับข้อยกเว้น) ดูเหมือนจะไม่ทำให้สิ่งต่างๆอ่านง่ายขึ้นและบางคำก็ทำให้อ่านได้น้อยลงในความคิดของฉัน

เนื่องจากคุณไม่สามารถควบคุมแหล่งที่มาที่สร้างขึ้นได้และสมมติว่าคุณจำเป็นต้องเข้าถึงฟิลด์ที่ซ้อนกันอย่างลึกซึ้งเพียงไม่กี่ช่องที่นี่จากนั้นฉันขอแนะนำให้ใช้วิธีการรวมการเข้าถึงที่ซ้อนกันลึก ๆ

private int getFooBarBazInt() {
    if (wsObject.getFoo() == null) return -1;
    if (wsObject.getFoo().getBar() == null) return -1;
    if (wsObject.getFoo().getBar().getBaz() == null) return -1;
    return wsObject.getFoo().getBar().getBaz().getInt();
}

หากคุณพบว่าตัวเองกำลังเขียนวิธีการเหล่านี้จำนวนมากหรือหากคุณพบว่าตัวเองถูกล่อลวงให้สร้างวิธีการแบบคงที่สาธารณะเหล่านี้ฉันจะสร้างแบบจำลองวัตถุแยกต่างหากโดยซ้อนกันตามที่คุณต้องการโดยมีเฉพาะฟิลด์ที่คุณสนใจและแปลงจากเว็บ บริการโมเดลวัตถุให้กับโมเดลวัตถุของคุณ

เมื่อคุณกำลังสื่อสารกับบริการเว็บระยะไกลเป็นเรื่องปกติมากที่จะมี "โดเมนระยะไกล" และ "โดเมนแอปพลิเคชัน" และสลับไปมาระหว่างสองโดเมน โดเมนระยะไกลมักจะถูก จำกัด โดยเว็บโปรโตคอล (ตัวอย่างเช่นคุณไม่สามารถส่งเมธอดตัวช่วยกลับไปกลับมาในบริการ RESTful ที่แท้จริงและโมเดลอ็อบเจ็กต์ที่ซ้อนกันลึกเป็นเรื่องปกติเพื่อหลีกเลี่ยงการเรียก API หลายครั้ง) ดังนั้นจึงไม่เหมาะสำหรับการใช้โดยตรงใน ลูกค้าของคุณ

ตัวอย่างเช่น:

public static class MyFoo {

    private int barBazInt;

    public MyFoo(Foo foo) {
        this.barBazInt = parseBarBazInt();
    }

    public int getBarBazInt() {
        return barBazInt;
    }

    private int parseFooBarBazInt(Foo foo) {
        if (foo() == null) return -1;
        if (foo().getBar() == null) return -1;
        if (foo().getBar().getBaz() == null) return -1;
        return foo().getBar().getBaz().getInt();
    }

}

1
return wsObject.getFooBarBazInt();

โดยใช้กฎแห่ง Demeter

class WsObject
{
    FooObject foo;
    ..
    Integer getFooBarBazInt()
    {
        if(foo != null) return foo.getBarBazInt();
        else return null;
    }
}

class FooObject
{
    BarObject bar;
    ..
    Integer getBarBazInt()
    {
        if(bar != null) return bar.getBazInt();
        else return null;
    }
}

class BarObject
{
    BazObject baz;
    ..
    Integer getBazInt()
    {
        if(baz != null) return baz.getInt();
        else return null;
    }
}

class BazObject
{
    Integer myInt;
    ..
    Integer getInt()
    {
        return myInt;
    }
}

0

ให้คำตอบที่ดูเหมือนจะแตกต่างจากคนอื่น ๆ

ฉันขอแนะนำให้คุณตรวจสอบNULLในifs

เหตุผล :

เราไม่ควรปล่อยโอกาสเดียวที่โปรแกรมของเราจะล่ม NullPointer ถูกสร้างขึ้นโดยระบบ พฤติกรรมของข้อยกเว้นระบบที่สร้างขึ้นไม่สามารถคาดการณ์ คุณไม่ควรปล่อยโปรแกรมของคุณไว้ในมือของระบบเมื่อคุณมีวิธีจัดการด้วยตัวคุณเองแล้ว และวางกลไกการจัดการ Exception เพื่อความปลอดภัยเป็นพิเศษ. !!

เพื่อให้รหัสของคุณอ่านง่ายให้ลองตรวจสอบเงื่อนไข:

if (wsObject.getFoo() == null || wsObject.getFoo().getBar() == null || wsObject.getFoo().getBar().getBaz() == null) 
   return -1;
else 
   return wsObject.getFoo().getBar().getBaz().getInt();

แก้ไข:

นี่คุณจะต้องเก็บค่าเหล่านี้wsObject.getFoo(), wsObject.getFoo().getBar(), wsObject.getFoo().getBar().getBaz()ตัวแปรบาง ฉันไม่ได้ทำเพราะฉันไม่รู้ประเภทการส่งคืนของฟังก์ชันนั้น

ข้อเสนอแนะใด ๆ จะชื่นชม .. !!


คุณคิดว่า getFoo () เป็นการดำเนินการที่ใช้เวลามากหรือไม่? คุณควรเก็บค่าที่ส่งคืนในตัวแปรอย่างไรก็ตามจะเป็นการสิ้นเปลืองหน่วยความจำ วิธีของคุณเหมาะสำหรับการเขียนโปรแกรมภาษาซี
xenteros

แต่บางครั้งก็ดีกว่าที่จะช้าไป 1 มิลลิวินาทีจากนั้นโปรแกรมจะล่ม @xenteros .. !!
Janki Gadhiya

getFoo () อาจได้รับค่าจากเซิร์ฟเวอร์ที่อยู่ในทวีปอื่น สามารถอยู่ได้ตลอดเวลา: นาที / ชั่วโมง ...
xenteros

wsObjectจะมีค่าที่ส่งคืนจาก Webservice .. !! จะเรียกใช้บริการอยู่แล้วและwsObjectจะได้รับXMLข้อมูลยาวเป็นเว็บบริการตอบกลับ .. !! ดังนั้นจึงไม่มีอะไรเหมือนกับเซิร์ฟเวอร์ที่ตั้งอยู่ในทวีปอื่นเพราะgetFoo()เป็นเพียงองค์ประกอบที่รับเมธอด getterไม่ใช่การเรียกใช้บริการเว็บ .. !! @xenteros
Janki Gadhiya

1
จากชื่อของ getters ฉันจะถือว่าพวกเขาส่งคืนวัตถุ Foo, Bar และ Baz: P ให้พิจารณาลบความปลอดภัยสองเท่าที่กล่าวถึงออกจากคำตอบของคุณด้วย ฉันไม่คิดว่ามันให้คุณค่าที่แท้จริงนอกเหนือจากมลพิษของรหัส ด้วยตัวแปรภายในที่มีสติและการตรวจสอบค่าว่างเราได้ทำมากเกินพอเพื่อให้แน่ใจว่าโค้ดถูกต้อง หากมีข้อยกเว้นเกิดขึ้นควรถือเป็นข้อยกเว้น
Marius K.

0

ฉันเขียนคลาสที่เรียกว่าSnagซึ่งให้คุณกำหนดเส้นทางเพื่อนำทางผ่านต้นไม้ของวัตถุ นี่คือตัวอย่างการใช้งาน:

Snag<Car, String> ENGINE_NAME = Snag.createForAndReturn(Car.class, String.class).toGet("engine.name").andReturnNullIfMissing();

หมายความว่าอินสแตนซ์ENGINE_NAMEจะเรียกCar?.getEngine()?.getName()อินสแตนซ์ที่ส่งผ่านไปยังอินสแตนซ์ได้อย่างมีประสิทธิภาพและส่งคืนnullหากการอ้างอิงใด ๆ ส่งกลับnull:

final String name =  ENGINE_NAME.get(firstCar);

ไม่มีการเผยแพร่บน Maven แต่หากใครพบว่าสิ่งนี้มีประโยชน์ก็อยู่ที่นี่ (ไม่มีการรับประกันแน่นอน!)

มันค่อนข้างธรรมดา แต่ดูเหมือนจะทำงานได้ดี เห็นได้ชัดว่ามันล้าสมัยกว่าด้วย Java เวอร์ชันล่าสุดและภาษา JVM อื่น ๆ ที่รองรับการนำทางที่ปลอดภัยหรือOptional.

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