ทำไม Java String จึงไม่มีวิธีการจัดการสตริงแบบคงที่


17

ทำไมนักออกแบบ Javaไม่สร้างวิธีการจัดการสตริงแบบคงที่ในjava.lang.Stringคลาส? วิธีการต่อไปนี้เป็นสิ่งที่ฉันอ้างถึง แต่คำถามสามารถขยายไปยังวิธีการไม่คงที่อื่น ๆ ในชั้นเรียนเช่นกัน

concat(String)                        substring(int, int)
replace(char, char)                   toLowerCase()
replace(CharSequence, CharSequence)   toLowerCase(Locale)
replaceAll(String, String)            toString()
replaceFirst(String, String)          toUpperCase()
split(String)                         toUpperCase(Locale)
split(String, int)                    trim()
substring(int)

การมีวิธีการเหล่านี้ในเวอร์ชันที่ไม่คงที่เท่านั้นจะบังคับให้มีการตรวจสอบ Null อย่างชัดเจนไม่ว่าที่ใดก็ต้องเรียกใช้ ยกตัวอย่างเช่นเพียงแค่โทรexample = example.trim()จะนำไปสู่NullPointerExceptionString example = nullถ้า ดังนั้นโปรแกรมเมอร์จะต้องทำการตรวจสอบ boilerplate null ต่อไปนี้:

if (example != null)
    example = example.trim();
// OR:
example = (example==null) ? null : example.trim();
example = (example==null) ? null : example.substring(5);

ฉันคิดว่ามันจะสะดวกกว่านี้มากหากStringมีวิธีคงที่ของเวอร์ชันเหล่านี้ (อาจเป็นแบบเฉพาะ ) ซึ่งจะใช้สตริงอินพุตเป็นอาร์กิวเมนต์แรก:

example = String.trim(example);
example = String.replace(example, 'a', 'b');
example = String.substring(example, 5);

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

ทำไมนักออกแบบ Java ไม่คิดเรื่องนี้เมื่อพวกเขาออกแบบStringคลาสใน Java 1 หรือ Java 2 หรือแม้แต่เพิ่มฟังก์ชั่นดังกล่าวใน Java เวอร์ชันที่ใหม่กว่า?


17
ฉันขอแนะนำให้แทนที่ "ทำไมนักออกแบบ Java ไม่คิดว่า X" ด้วย "ทำไมนักออกแบบ Java ตัดสินใจต่อ X" ให้เครดิตพื้นฐานแก่พวกเขาที่ไม่ได้ตาบอดต่อตัวเลือก
Avner Shahar-Kashtan

5
nullเป็นสถานะพิเศษและควรได้รับการจัดการอย่างชัดเจน
CodesInChaos

2
@ KonradMorawski: โดยส่วนตัวแล้วฉันพบว่าการใช้งานส่วนขยายผิดวิธี หากคุณมีค่าว่างคุณกำลังพยายามเรียกใช้วิธีการใดบนโลกนี้คุณจะสับสนทุกคนที่อ่านรหัสนั้น มันเป็นการปรับปรุงที่ไม่ดีของMaybe<T>ประเภทฉันเดา?
Phoshi

1
@Phoshi หนึ่งมีเก็บไว้ในใจว่าวิธีการนี้จะไม่ขยายวิธีการจริงพวกเขากำลังเพียงน้ำตาลไวยากรณ์ แต่ฉันยอมรับว่ามันขัดแย้ง ฉันหวังว่า C # / Java ให้ความปลอดภัยแบบ syntactic null แบบในตัวเช่น - say - Kotlin string name = employee?.personalData?.name. เช่นเดียวกับทางลัดสำหรับif (employee != null)s ซ้ำทั้งหมดเหล่านี้ คำถาม SO ที่เกี่ยวข้อง: stackoverflow.com/questions/1196031/…
Konrad Morawski

2
@ADTC Erm คุณรู้หรือไม่ว่าโปรแกรมไม่สามารถคาดการณ์ล่วงหน้าว่าค่านั้นเป็นโมฆะใช่ไหม - คุณควรกำหนดสัญญาระหว่างอินเทอร์เฟซของคุณในแบบที่คุณสามารถมั่นใจได้ว่าค่าที่ได้รับอนุญาตให้เป็นโมฆะหรือไม่ การตรวจสอบที่ว่างเปล่าทุกที่หมายความว่าคุณมีปัญหาการออกแบบโปรแกรม
Uooo

คำตอบ:


30

การกลับมาเป็นโมฆะทำให้ฉันมีเหตุผลตั้งแต่จัดการกับสตริง null ควรส่งผลให้เป็นสตริงว่างไม่ใช่ข้อผิดพลาด

นั่นคือความคิดเห็นของคุณ คนอื่นอาจโต้แย้งว่าการดำเนินการของสตริงบนวัตถุที่เป็นโมฆะซึ่งไม่ได้มีสตริงที่ไม่มีเหตุผลและควรโยนข้อยกเว้น

เหตุใด "นักออกแบบ Java" จึงทำหรือไม่ทำสิ่งที่ยากเกินกว่าจะทำได้

มีไลบรารีอยู่แล้วซึ่งสามารถทำการดำเนินการกับสตริงแบบ null-safe ได้เช่นStringUtilsของ Apache Commons คุณสามารถใช้มันหรือไลบรารีที่คล้ายกันได้หากคุณต้องการ


นอกจากนี้ขึ้นอยู่กับความคิดเห็นของคุณ

การอ่านความคิดเห็นดูเหมือนว่าปัญหาที่แท้จริงที่คุณเผชิญคือคุณต้องตรวจสอบnullรหัสของคุณทั้งหมด นั่นอาจเป็นตัวบ่งชี้การออกแบบโปรแกรมที่ไม่ดีโดยไม่มีสัญญาที่ชัดเจนระหว่างอินเตอร์เฟส คุณอาจต้องการอ่านคำสั่งหลีกเลี่ยง“! = null” ใน Java?


1
ขอบคุณสำหรับความคิดเห็นของคุณ ฉันเดาว่าคำถามจริงคือทำไมเราต้องพึ่งพาห้องสมุดภายนอกหรือชั้นเรียนทำที่บ้านเมื่อคุณสมบัติพื้นฐานดังกล่าวสามารถเป็นส่วนหนึ่งของ Java มาตรฐานได้
ADTC

4
@ADTC ให้ตั้งคำถามอีกด้าน: ทำไม "นักออกแบบ Java" ควรรวมบางสิ่งบางอย่างไว้ในภาษาถ้ามีไลบรารีที่ดีจำนวนมากอยู่ในนั้นทดสอบและจัดทำเป็นเอกสารดีหรือไม่ วิธีการกำหนด "คุณสมบัติพื้นฐาน" นั้นขึ้นอยู่กับความคิดเห็น ไม่ทุกโครงการส่วนใหญ่ต้องการไลบรารีภายนอกสำหรับ "ฟังก์ชันการทำงานพื้นฐาน" (การทดสอบหน่วยการเยาะเย้ยวันที่และเวลา ... ) ใช่หรือไม่ มันไม่ใช่เรื่องใหญ่ใช่มั้ย
Uooo

วิธีหนึ่งในการจัดการกับ nulls คือการใช้ Guava's Optional- code.google.com/p/guava-l
ไลบรารี/wiki/…

10

IMO ทั้งหมด "ถ้าหาเรื่องเป็นโมฆะคืนโมฆะ" วิธีการเขียนโดยไม่จำเป็นต้องเพิ่มความซับซ้อนของวงจรของโปรแกรม

Java libs ก่อนหน้านี้ใช้วิธีส่งคืน null แต่กลุ่ม JDK จะป้องกัน null ด้วยข้อยกเว้นเสมอ

เมื่อเวลาผ่านไปฉันคิดว่าวิธีการหลังได้ออกมาเป็นผู้ชนะที่ชัดเจน

ทำไม? เนื่องจากเขตข้อมูลว่างจะทำลายหลักการจำนวนมาก คุณไม่สามารถปฏิบัติต่อพวกเขาในฐานะสมาชิกของคลาส polymorphic ซึ่งหมายความว่าคุณต้องเขียนโค้ดกรณีพิเศษให้เป็นโมฆะและด้วยเหตุนี้ความซับซ้อนในวงจรของคุณจึงสูงขึ้นเมื่อคุณต้องสมมติว่าสิ่งต่าง ๆ เป็นโมฆะ

เพื่อแก้ไขปัญหาของคุณให้พิจารณาใช้รูปแบบวัตถุ null แทนการใช้เขตข้อมูล null


2
แต่Stringไม่ใช่ polymorphic ไม่ใช่เหรอ? และคุณจะใช้รูปแบบวัตถุ null สำหรับชนิดที่มีอยู่แล้วเช่น String ได้อย่างไร
svick

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

@AlexanderTorstling: สาขาของประเภทค่าเริ่มต้นให้เป็นศูนย์มากกว่าint nullแนวคิดควรเป็นไปได้ที่จะมีstringประเภทที่ค่าเริ่มต้นจะเป็นสตริงว่างเปล่าแทนที่จะเป็นnull[ประเภทดังกล่าวอาจหมายถึงStringสิ่งที่intต้องการInteger] ความจริงที่ว่าที่ไม่ว่างเปล่าstringจะมีการอ้างอิงภายในไปยังวัตถุฮีปนั้นจะเป็นรายละเอียดการใช้งาน ไม่มีเหตุผลใดที่มันไม่สามารถแสดงความหมายเหมือนแบบดั้งเดิมได้
supercat

@supercat: เห็นด้วย ฉันคิดว่ามันจะดีกว่าที่จะห้ามค่าว่างสำหรับการอ้างอิงยกเว้นว่าเปิดใช้งานอย่างชัดเจน ค่าเริ่มต้นไม่ใช่เขตข้อมูลโมฆะและสุดท้าย หลายประเภทมีวัตถุที่มีพฤติกรรมเป็นโมฆะ
Alexander Torstling

@AlexanderTorstling: มีสถานที่จัดเก็บทุกประเภทเริ่มต้นทุกไบต์ศูนย์และการให้ที่ประเภทโครงสร้างสามารถกำหนดผ่านทุกไบต์คัดลอกง่ายมากกรอบ แต่สวยมากหมายความว่าประเภทที่ไม่แน่นอนความหมายอ้างอิงจะต้องเริ่มต้นกับ โมฆะ อย่างไรก็ตามจะมีประโยชน์อย่างไรหากมีกรอบการสนับสนุนสำหรับประเภทค่าที่จะสรุปการอ้างอิงเดียวและจะ "ทำเครื่องหมาย" เป็น - และสามารถยกเลิกจาก - ประเภทการอ้างอิงนั้นได้
supercat

3

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

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


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

2
ณ ตอนนี้คุณมีString.format(คงที่) "something %s".format(id)แต่คุณไม่สามารถทำ
Konrad Morawski

@adtc: เพราะมันไม่ใช่คุณสมบัติพื้นฐานของภาษาในการทำผ่านคลาสคงที่ เริ่มต้นจากสถานที่นั้นมีเหตุผลมากมายที่จะไม่ทำเช่นนั้น - การขยายรหัส / รหัสที่ไม่จำเป็นฟังก์ชันการทำงานที่ซ้ำซ้อนต้นทุนการพัฒนา / การบำรุงรักษา
jmoreno

-2

ใน java สตริงนั้นเป็นวัตถุ นั่นเป็นตัวเลือกการออกแบบ

การอ้างอิงวัตถุสามารถเป็นโมฆะและเป็นโมฆะหากไม่มีการกำหนดวัตถุให้ ถ้าคุณเรียกใช้วัตถุดังกล่าว NullPointerException จะถูกส่งออกไป นั่นเป็นพฤติกรรมที่เป็นมาตรฐาน

นักออกแบบ Java เลือกที่จะมีสตริงเป็นวัตถุและมีวิธีการเหล่านั้นที่มีข้อยกเว้น null-pointer คือสิ่งที่คุณได้รับหากคุณต้องการให้สตริงเป็นวัตถุ

ทำไมนักออกแบบ Java ไม่คิดเรื่องนี้เมื่อพวกเขาออกแบบคลาส String ใน Java 1 หรือ Java 2 หรือแม้แต่เพิ่มฟังก์ชันการทำงานดังกล่าวในเวอร์ชัน Java ในภายหลัง

พวกเขาอาจคิดเกี่ยวกับมันและเลือกที่จะรวมพฤติกรรม oo


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

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

4
เพียงเพราะสตริงเป็นวัตถุไม่ได้หมายความว่าคลาส String ไม่สามารถมีวิธีคงที่ และแน่นอนว่ามันมีอยู่แล้วเช่น String.format. (เหมือนกันใน C # โดยวิธี) ดังนั้นหากเป็นตัวเลือกการออกแบบมันไม่สามารถมาจากความจริงที่ว่าสตริงเป็นวัตถุและมันไม่ได้ถูกนำมาใช้อย่างสม่ำเสมอ
Konrad Morawski

@PerterB ฉันจะไม่บ่นถ้าอย่างน้อยวิธีการดังกล่าวมีให้ในStringsคลาสยูทิลิตี้เช่นเรามีArraysคลาสยูทิลิตี้ ( แม้ว่าฉันเข้าใจว่ามันถูกสร้างขึ้นมาจากความจำเป็นที่แท้จริงเนื่องจากอาร์เรย์เป็นชนิดข้ามแปลก ๆ ระหว่างวัตถุดั้งเดิมและวัตถุ: ) ) .. ตราบใดที่มันเป็นส่วนหนึ่งของ Java มาตรฐานและไม่ต้องการการพึ่งพา
ADTC
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.