ทำไมการใช้ System.out.println () แย่มาก? [ปิด]


18

แน่นอนว่าเป็นการดีมากที่จะใช้กรอบการบันทึกสำหรับข้อความแสดงข้อผิดพลาดหรือคำเตือน แต่บางครั้งฉันใช้ System.out.println () ถ้าฉันต้องการลองสิ่งใหม่ ๆ ในเวลาอันสั้น

การใช้ System.out.println () นั้นแย่มากจริง ๆ หรือไม่สำหรับการทดสอบอย่างรวดเร็ว?


3
ไม่มันเป็นการทดสอบด่วนใครจะสน?
ไบรอัน Boettcher

10
ใครบอกว่ามันแย่ ทางเลือกคืออะไร
James

1
เครื่องมือตรวจสอบรหัสคงที่ @Kayser ไม่เหมาะสมสำหรับการทดสอบอย่างรวดเร็ว - มีไว้สำหรับรหัสที่คุณต้องการพัฒนาร่วมกับผู้อื่น (หรือผู้อื่นจะต้องเข้าใจ) บทเรียนที่ฉันดูเหมือนจะเรียนรู้ในปีนี้คือมีพื้นที่ปัญหาที่แตกต่างกันมากแม้ในวันทำงานที่ต้องใช้ชุดเครื่องมือและการปฏิบัติที่แตกต่างกันมาก ดังนั้นสำหรับการทดสอบอย่างรวดเร็วของคุณให้เชยมันและใช้ Groovy :)
Bill K

1
ลองใช้System.err.println()และดูว่าเกิดอะไรขึ้น ฉันเดาว่าเครื่องมือนี้คิดว่าคุณใช้System.outเพื่อจุดประสงค์ที่ผิด
Izkata

2
ปัญหาหลักคือการปรับขนาดและการควบคุม หากคุณมีข้อความเหล่านี้หลายล้านข้อความคุณจะเห็นสิ่งที่คุณต้องการดูได้อย่างไร หากคุณต้องการตอบสนองต่อสิ่งเหล่านี้คุณจะทำอย่างไรในทางโปรแกรม เฟรมเวิร์กการบันทึกมักเป็นความคิดทั้งสองที่ใช้กับ System.out

คำตอบ:


18

ตามที่เปิดเผยในความคิดเห็นคำถามจริงที่ถูกถามคือทำไมเครื่องมือวิเคราะห์รหัสแบบคงที่ใช้ธงของ System.out.println?

เหตุผลคือการส่งข้อความไปยัง stdout มักไม่เหมาะสมในสภาพแวดล้อมการผลิต หากคุณกำลังเข้ารหัสไลบรารีไลบรารีควรส่งคืนข้อมูลไปยังผู้เรียกไม่ใช่พิมพ์ไปที่ stdout หากคุณกำลังเข้ารหัสแอป GUI ข้อมูลจะถูกนำเสนอให้กับผู้ใช้ไม่ใช่ตำแหน่งที่เกิด stdout สำหรับชี้ (ซึ่งอาจไม่มีที่ใด) หากคุณกำลังเข้ารหัสเซิร์ฟเวอร์ (หรือสิ่งที่ทำงานในคอนเทนเนอร์ฝั่งเซิร์ฟเวอร์) คุณควรใช้สิ่งอำนวยความสะดวกการบันทึกข้อมูลใด ๆ ที่เฟรมเวิร์กได้จัดเตรียมไว้ และอื่น ๆ

แต่ถ้าคุณใช้ println สำหรับการดีบั๊กหรือการพัฒนาหรือคุณกำลังเขียนโปรแกรมและอ่าน stdin และเขียนไปยัง stdout println ก็ใช้ได้อย่างสมบูรณ์แบบ ไม่มีอะไรผิดปกติสำหรับกรณีเหล่านั้น


3
คำตอบที่ดี ขอบคุณ .. +1 สำหรับ "หากคุณกำลังเขียนรหัสแอป GUI ข้อมูลควรจะถูกนำเสนอให้กับผู้ใช้ไม่ใช่ที่จุด stdout เกิดขึ้น (ซึ่งอาจจะไม่มีที่ไหนเลย)"
Kayser

10

ทั้งหมดได้stdoutรับการบัฟเฟอร์และเป็นไปได้ว่าโปรแกรมของคุณจะหยุดทำงานหลังจากที่คุณโทรprintln()แต่ก่อนที่จะถึงหน้าจอ

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


ล่ามไพ ธ อนอย่างน้อยสองตัวพยายามอย่างหนักที่จะล้างไฟล์ที่เปิดอยู่ทั้งหมดก่อนออกแม้ว่าการออกจะเกิดจากข้อยกเว้นที่ไม่ได้เรียกใช้ JVM ไม่ได้ทำสิ่งที่คล้ายกันใช่ไหม

1
@delnan อาจเป็นไปได้ แต่มีอะไรเกิดขึ้น (โค้ดที่วูบวาบ stdout อาจเป็นที่ที่ปัญหาเกิดขึ้นเธรดที่คุณกำลังทำงานอยู่อาจถูกปิดอย่างแรงกระบวนการปัจจุบันอาจถูกเททิ้งจากหน่วยความจำอย่างแรงโดยระบบปฏิบัติการ) อย่าใช้ชีวิตรอบงบของฉัน แค่ระวังให้ดี
riwalk

1
รหัสที่วูบวาบ stdout อยู่ใน VM เองและไม่ได้รับผลกระทบจากข้อผิดพลาดในภาษาที่ VM ดำเนินการ จุดดีเกี่ยวกับการสิ้นสุดกระบวนการบังคับ แต่โปรดทราบว่าเช่น SIGTERM ของ Unix และสัญญาณอื่น ๆ ส่วนใหญ่สามารถจับได้ว่าจะล้างข้อมูลเช่นนี้ - ไม่ทำงานกับ SIGKILL ที่รุนแรงกว่านี้

2
ฉันไม่คิดว่าฉันเคยเห็นสิ่งนี้หรือได้ยินสิ่งนี้เกิดขึ้นแม้ว่าฉันจะเห็นปัญหาอื่นแล้วก็ตาม ปัญหานี้ก็ไม่น่าจะดีขึ้นด้วยเครื่องมือเช่นคนตัดไม้เพราะพวกเขามีแนวโน้มที่จะใช้ System.out เป็นเครื่องมือพื้นฐาน
Bill K

@delnan อย่าสันนิษฐานว่ารหัสการล้างข้อมูลของคุณรับประกันว่าจะรัน ... และไม่เคยใส่รหัสการทำธุรกรรมทางธุรกิจที่สำคัญในที่สุดบล็อก;) System.out นั้นดีสำหรับการดีบัก แต่ระวังบัฟเฟอร์
สตีเวน

8

System.outBufferedOutputStreamเป็นเพียงการห่อ นี่จะคล้ายกับเฟรมเวิร์กการบันทึกใด ๆ ที่คุณจะใช้เฟรมเวิร์กเพียงแค่ให้การทำงานมากขึ้นในรูปแบบของการกำหนดค่าและปลายทางของล็อกเอาต์พุตของคุณ


4
นี่ไม่ได้ตอบคำถามจริงๆ "มันแย่เหรอ?"
sergserg

@Berg - เพราะส่วนหนึ่งของคำถามนั้นขึ้นอยู่กับบริบทโดยสมบูรณ์ (หรือเพียงแค่ไม่เลวร้าย)
Spinning_plate

7

มันไม่ดีถ้าคุณกำลังทำงานในโปรแกรมที่ไม่สำคัญและคุณ

  • ใช้ System.out เป็น crutch แทนการทดสอบหน่วยอัตโนมัติ (JUnit)
  • ใช้เวลามากมายในการสร้างและลบหรือแสดงความคิดเห็น / ไม่พูดคำสั่ง System.out

1
IDE ส่วนใหญ่ควรมีฮ็อตคีย์สำหรับการเติมข้อความอัตโนมัติของ System.out.println แสดงความคิดเห็น / ไม่แสดงความคิดเห็นบรรทัดและลบบรรทัด คุณอยู่ในหลักการที่จะพยายามหลีกเลี่ยงการใช้งานมากเกินไป แต่อย่างน้อยคุณก็สามารถประหยัดเวลาได้ด้วยวิธีนี้
สตีเวน

7

มีข้อควรระวังบางประการเกี่ยวกับการใช้System.outแม้ในรหัสการอนุญาต

ปัญหาหนึ่งที่สำคัญก็คือว่ามันมักจะช้า ตัวอย่างเช่นหากคุณกำลังพยายามหาแนวคิดคร่าวๆเกี่ยวกับความเร็วของโค้ดบางอัน (โปรดทราบว่าmicrobenchmarks นั้นยาก ) จากนั้นการเพิ่มซิงเกิ้ลSystem.out.println()ที่ใดก็ได้สามารถทำให้เวลาของคุณยุ่งเหยิงได้จริง ๆ (เพราะการซิงโครไนซ์ ปรากฏแก่ผู้ใช้ก่อนกลับมา)

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


ประสิทธิภาพเป็นข้อโต้แย้งที่ดี ..
Kayser

4

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

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

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


3

ฉันมักจะมีปัญหาที่ System.out.print ใช้ codepage "ระบบเริ่มต้น" ซึ่งมักจะเป็น UTF-8 ภายใต้ Linux แต่บางสิ่ง MS crapped ใน Windows

สิ่งนี้อาจนำไปสู่ตัวอักษรยูนิโค้ดที่พิมพ์หรือไม่ถูกต้องไปยังหน้าจอทั้งนี้ขึ้นอยู่กับตำแหน่งที่โปรแกรมทำงาน

ฉันจึงชอบ PrintWriter ที่กำหนดเองมากกว่า System.out


โดยสิ่งที่ MS crapped คุณหมายถึง CP1352 หรือ UTF16
โคลจอห์นสัน

@ColeJohnson: หน้าต่างคอนโซล Windows ยังคงติดอยู่ในยุคก่อน UTF16 อย่างไรก็ตามการใช้ sane IDE กับคอนโซลในตัวสามารถลดปัญหาดังกล่าวได้
โจอาคิมซาวเออร์

@ โคลจอห์นสัน - ฉันสามารถอยู่กับ CP 65001 (เช่น utf8) แต่ดูเหมือนว่าจะไม่มีวิธีที่จะได้รับสิ่งนี้เป็นเพจรหัส "ระบบเริ่มต้น" เมื่อคุณมีแป้นพิมพ์ภาษาเยอรมันคุณจะได้รับ CP 850 หรือบางอย่าง
Ingo

1

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

อย่างไรก็ตามนี่ไม่ได้เป็นการบอกว่ามันเป็นแนวทางที่ไม่ถูกต้อง ฉันใช้มันหลายครั้งเพื่อตรวจสอบการไหลเวียนของแอปพลิเคชั่นหลังจากเขียนโปรแกรม hijinks magic voodoo สีดำ


0

ไม่มีอะไรผิดปกติกับการใช้มันจะช่วยให้คุณคิดออกว่าเกิดอะไรขึ้น

แต่ถ้าเพื่อนร่วมงาน / devs / เครื่องมืออื่น ๆ ของคุณน่าหัวเราะคุณสามารถใช้Loggerหรือเริ่มทดสอบJunit ได้ตลอดเวลา !


0

ปัญหาที่ใหญ่ที่สุดที่เกิดขึ้นกับ Occational System.out.println อย่างที่ฉันเห็นคือมันเป็น "นิสัยที่ไม่ดี (tm)" หากคุณพบว่าตัวเองกำลังทำสิ่งนี้อยู่คุณอาจจะสามารถปรับปรุงประสิทธิภาพของตัวคุณเองได้โดยการใช้ตัวดีบักเกอร์ตัวโปรด

นอกจากนี้ด้วยดีบักเกอร์คุณทราบได้อย่างชัดเจนว่าเบรกพอยต์จะไม่ลื่นไหลในรหัสการผลิตของคุณในขณะที่อาจมี System.out.println

ในบันทึกย่อด้านข้างหากคุณเพียงแค่ทำการทดสอบอย่างรวดเร็วและยืนยันว่าไม่ได้ใช้ดีบักเกอร์ฉันคิดว่า System.out.println นั้นดีกว่าการใช้เฟรมเวิร์กการบันทึกเนื่องจากหากคุณทิ้งข้อความคำสั่ง log.debug ไว้โดยไม่ตั้งใจเมื่อคุณ เสร็จแล้วมันยากที่จะหยั่งรากออก


0

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

อันตรายของการลืมที่จะลบออกอาจเป็นสาเหตุที่ไม่เหมาะสม


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