หมายเหตุ : ฉันกำลังดำเนินการกับคู่มือเวอร์ชัน 2 และต้องการความช่วยเหลือจากคุณ! โปรดใช้แบบฟอร์มนี้เพื่อให้ข้อเสนอแนะเกี่ยวกับสิ่งที่คุณคิดว่าควรจะมีในเวอร์ชันถัดไป ขอบคุณ!
Java เป็นหนึ่งในภาษาการเขียนโปรแกรมที่ได้รับความนิยมมากที่สุด แต่ดูเหมือนจะไม่มีใครชอบใช้มัน จริงๆ แล้ว Java เป็นภาษาโปรแกรมที่ดี และเนื่องจาก Java 8 เปิดตัวเมื่อเร็วๆ นี้ ฉันจึงตัดสินใจรวบรวมรายการไลบรารี แนวทางปฏิบัติ และเครื่องมือต่างๆ เพื่อทำให้การใช้ Java ดีขึ้น "ดีกว่า" เป็นเรื่องส่วนตัว ดังนั้นฉันขอแนะนำให้นำส่วนที่ตรงกับคุณมาใช้ แทนที่จะพยายามใช้ทั้งหมดพร้อมกัน อย่าลังเลที่จะส่งคำขอดึงเพื่อแนะนำการเพิ่มเติม
บทความนี้เดิมถูกโพสต์ในบล็อกของฉัน
อ่านสิ่งนี้ในภาษาอื่น: อังกฤษ, 简体中文
ตามเนื้อผ้า Java ได้รับการโปรแกรมในรูปแบบ JavaBean ระดับองค์กรที่ละเอียดมาก สไตล์ใหม่สะอาดตา ถูกต้องมากขึ้น และสบายตายิ่งขึ้น
สิ่งที่ง่ายที่สุดอย่างหนึ่งที่เราในฐานะโปรแกรมเมอร์ทำคือการส่งข้อมูล วิธีดั้งเดิมในการทำเช่นนี้คือการกำหนด JavaBean:
public class DataHolder {
private String data ;
public DataHolder () {
}
public void setData ( String data ) {
this . data = data ;
}
public String getData () {
return this . data ;
}
}
นี่เป็นเรื่องละเอียดและสิ้นเปลือง แม้ว่า IDE ของคุณจะสร้างโค้ดนี้โดยอัตโนมัติ แต่ก็ถือเป็นการสิ้นเปลือง ดังนั้นอย่าทำเช่นนี้
แต่ฉันชอบสไตล์การเขียนคลาส C struct ที่เก็บข้อมูลเท่านั้น:
public class DataHolder {
public final String data ;
public DataHolder ( String data ) {
this . data = data ;
}
}
นี่คือการลดจำนวนบรรทัดของโค้ดลงครึ่งหนึ่ง นอกจากนี้ คลาสนี้จะไม่เปลี่ยนรูปเว้นแต่คุณจะขยายออกไป ดังนั้นเราจึงสามารถให้เหตุผลได้ง่ายขึ้น เนื่องจากเรารู้ว่าไม่สามารถเปลี่ยนแปลงได้
หากคุณกำลังจัดเก็บออบเจ็กต์ เช่น แผนที่หรือรายการที่สามารถแก้ไขได้ง่าย คุณควรใช้ ImmutableMap หรือ ImmutableList แทน ซึ่งจะกล่าวถึงในหัวข้อเกี่ยวกับความไม่เปลี่ยนรูป
หากคุณมีอ็อบเจ็กต์ที่ค่อนข้างซับซ้อนซึ่งคุณต้องการสร้างโครงสร้าง ให้พิจารณารูปแบบตัวสร้าง
คุณสร้างคลาสภายในแบบคงที่ซึ่งจะสร้างวัตถุของคุณ มันใช้สถานะที่ไม่แน่นอน แต่ทันทีที่คุณเรียก build มันจะปล่อยวัตถุที่ไม่เปลี่ยนรูปออกมา
ลองนึกภาพเรามี DataHolder ที่ซับซ้อนกว่านี้ ผู้สร้างมันอาจจะมีลักษณะดังนี้:
public class ComplicatedDataHolder {
public final String data ;
public final int num ;
// lots more fields and a constructor
public static class Builder {
private String data ;
private int num ;
public Builder data ( String data ) {
this . data = data ;
return this ;
}
public Builder num ( int num ) {
this . num = num ;
return this ;
}
public ComplicatedDataHolder build () {
return new ComplicatedDataHolder ( data , num ); // etc
}
}
}
จากนั้นใช้:
final ComplicatedDataHolder cdh = new ComplicatedDataHolder . Builder ()
. data ( "set this" )
. num ( 523 )
. build ();
มีตัวอย่างที่ดีกว่าของ Builders ในที่อื่น แต่สิ่งนี้น่าจะทำให้คุณได้สัมผัสว่ามันเป็นอย่างไร สิ่งนี้ลงเอยด้วยรูปแบบสำเร็จรูปจำนวนมากที่เราพยายามหลีกเลี่ยง แต่จะทำให้คุณได้รับวัตถุที่ไม่เปลี่ยนรูปและมีอินเทอร์เฟซที่คล่องแคล่วมาก
แทนที่จะสร้างออบเจ็กต์ตัวสร้างด้วยมือ ให้พิจารณาใช้หนึ่งในไลบรารีจำนวนมากที่สามารถช่วยคุณสร้างตัวสร้างได้
หากคุณสร้างอ็อบเจ็กต์ที่ไม่เปลี่ยนรูปจำนวนมากด้วยมือ ให้พิจารณาใช้ตัวประมวลผลคำอธิบายประกอบเพื่อสร้างอ็อบเจ็กต์เหล่านั้นจากอินเทอร์เฟซโดยอัตโนมัติ วิธีนี้จะช่วยลดโค้ดสำเร็จรูป ลดความน่าจะเป็นของจุดบกพร่อง และส่งเสริมความไม่เปลี่ยนรูป ดูการนำเสนอนี้สำหรับการอภิปรายที่น่าสนใจเกี่ยวกับปัญหาบางประการเกี่ยวกับรูปแบบการเข้ารหัส Java ปกติ
ไลบรารีการสร้างโค้ดที่ยอดเยี่ยมบางตัวนั้นไม่เปลี่ยนรูป ซึ่งเป็นค่าอัตโนมัติของ Google และลอมบอก
ควรใช้ข้อยกเว้นที่ได้รับการตรวจสอบด้วยความระมัดระวัง หากเลย พวกเขาบังคับให้ผู้ใช้ของคุณเพิ่มบล็อก try/catch จำนวนมาก และล้อมข้อยกเว้นของคุณด้วยตนเอง ดีกว่าคือทำให้ข้อยกเว้นของคุณขยาย RuntimeException แทน วิธีนี้ช่วยให้ผู้ใช้ของคุณสามารถจัดการกับข้อยกเว้นของคุณได้ในแบบที่พวกเขาต้องการ แทนที่จะบังคับให้พวกเขาจัดการ/ประกาศว่าจะมีการ Throw ทุกครั้ง ซึ่งจะทำให้โค้ดเสียหาย
เคล็ดลับที่ดีประการหนึ่งคือการใส่ RuntimeExceptions ไว้ในการประกาศการส่งเมธอดของคุณ สิ่งนี้ไม่มีผลกระทบต่อคอมไพเลอร์ แต่จะแจ้งให้ผู้ใช้ของคุณทราบผ่านเอกสารประกอบว่าข้อยกเว้นเหล่านี้สามารถเกิดขึ้นได้
นี่เป็นส่วนวิศวกรรมซอฟต์แวร์มากกว่าส่วน Java แต่หนึ่งในวิธีที่ดีที่สุดในการเขียนซอฟต์แวร์ที่ทดสอบได้คือการใช้ dependency injector (DI) เนื่องจาก Java สนับสนุนการออกแบบ OO อย่างยิ่ง เพื่อสร้างซอฟต์แวร์ที่ทดสอบได้ คุณจึงจำเป็นต้องใช้ DI
ใน Java โดยทั่วไปจะทำสิ่งนี้ด้วย Spring Framework มีการเดินสายตามโค้ดหรือการเดินสายตามการกำหนดค่า XML หากคุณใช้การกำหนดค่า XML สิ่งสำคัญคือคุณต้องไม่ใช้ Spring มากเกินไปเนื่องจากรูปแบบการกำหนดค่าที่ใช้ XML ไม่ควรมีตรรกะหรือโครงสร้างการควบคุมใน XML อย่างแน่นอน ควรฉีดการพึ่งพาเท่านั้น
ทางเลือกที่ดีในการใช้ Spring คือห้องสมุด Dagger ของ Google และ Square หรือ Guice ของ Google พวกเขาไม่ใช้รูปแบบไฟล์การกำหนดค่า XML ของ Spring แต่กลับใส่ตรรกะการฉีดในคำอธิบายประกอบและในโค้ดแทน
พยายามหลีกเลี่ยงการใช้ค่าว่างเมื่อทำได้ อย่าส่งคืนคอลเล็กชันที่เป็นค่าว่าง เมื่อคุณควรส่งคืนคอลเล็กชันว่างแทน หากคุณกำลังจะใช้ null ให้พิจารณาคำอธิบายประกอบ @Nullable IntelliJ IDEA มีการสนับสนุนในตัวสำหรับคำอธิบายประกอบ @Nullable
อ่านเพิ่มเติมเกี่ยวกับเหตุใดจึงไม่ใช้ค่าว่างในข้อผิดพลาดที่เลวร้ายที่สุดของวิทยาการคอมพิวเตอร์
หากคุณใช้ Java 8 คุณสามารถใช้ประเภทตัวเลือกใหม่ที่ยอดเยี่ยมได้ หากค่าอาจมีหรือไม่มี ให้ล้อมไว้ในคลาส Optional ดังนี้:
public class FooWidget {
private final String data ;
private final Optional < Bar > bar ;
public FooWidget ( String data ) {
this ( data , Optional . empty ());
}
public FooWidget ( String data , Optional < Bar > bar ) {
this . data = data ;
this . bar = bar ;
}
public Optional < Bar > getBar () {
return bar ;
}
}
ตอนนี้เป็นที่ชัดเจนแล้วว่า ข้อมูล จะไม่มีวันเป็นโมฆะ แต่ แถบ อาจมีหรือไม่มีก็ได้ Optional มีวิธีการเช่น isPresent ซึ่งอาจทำให้รู้สึกว่ามีความแตกต่างไม่มากจากการตรวจสอบ null แต่ช่วยให้คุณเขียนคำสั่งเช่น:
final Optional < FooWidget > fooWidget = maybeGetFooWidget ();
final Baz baz = fooWidget . flatMap ( FooWidget :: getBar )
. flatMap ( BarWidget :: getBaz )
. orElse ( defaultBaz );
ซึ่งจะดีกว่าการถูกล่ามโซ่มากหากตรวจสอบค่าว่าง ข้อเสียเพียงอย่างเดียวของการใช้ Optional คือไลบรารีมาตรฐานไม่มีการสนับสนุน Optional ที่ดี ดังนั้นจึงจำเป็นต้องมีการจัดการกับค่าว่างที่นั่น
เว้นแต่คุณจะมีเหตุผลที่ดีในการทำให้มันเป็นอย่างอื่น ตัวแปร คลาส และคอลเลกชั่นควรจะไม่เปลี่ยนรูป
ตัวแปรสามารถทำให้ไม่เปลี่ยนรูปได้ด้วย Final :
final FooWidget fooWidget ;
if ( condition ()) {
fooWidget = getWidget ();
} else {
try {
fooWidget = cachedFooWidget . get ();
} catch ( CachingException e ) {
log . error ( "Couldn't get cached value" , e );
throw e ;
}
}
// fooWidget is guaranteed to be set here
ตอนนี้คุณสามารถมั่นใจได้ว่า fooWidget จะไม่ถูกกำหนดใหม่โดยไม่ได้ตั้งใจ คำหลัก สุดท้าย ใช้งานได้กับบล็อก if/else และบล็อก try/catch แน่นอนว่า หากตัว fooWidget ไม่สามารถเปลี่ยนรูปแบบได้ คุณก็สามารถเปลี่ยนมันได้อย่างง่ายดาย
คอลเลกชันควรใช้คลาส Guava ImmutableMap, ImmutableList หรือ ImmutableSet ทุกครั้งที่เป็นไปได้ สิ่งเหล่านี้มีตัวสร้างเพื่อให้คุณสามารถสร้างพวกมันขึ้นมาแบบไดนามิก จากนั้นทำเครื่องหมายว่าพวกมันไม่เปลี่ยนรูปโดยการเรียกเมธอด build
คลาสควรทำให้ไม่เปลี่ยนรูปโดยการประกาศฟิลด์ที่ไม่เปลี่ยนรูป (ผ่าน Final ) และโดยใช้คอลเลกชันที่ไม่เปลี่ยนรูป คุณสามารถเลือกทำให้คลาสเป็นคลาส สุดท้ายได้ เพื่อไม่ให้ขยายและทำให้ไม่แน่นอนได้
ระวังหากคุณพบว่าตัวเองเพิ่มวิธีการมากมายให้กับคลาส Util
public class MiscUtil {
public static String frobnicateString ( String base , int times ) {
// ... etc
}
public static void throwIfCondition ( boolean condition , String msg ) {
// ... etc
}
}
คลาสเหล่านี้ในตอนแรกดูน่าสนใจเพราะวิธีการต่างๆ ที่เข้าไปนั้นไม่ได้อยู่ในที่ใดที่หนึ่งจริงๆ ดังนั้นคุณจึงโยนมันทั้งหมดมาที่นี่ในนามของการใช้โค้ดซ้ำ
การรักษาจะเลวร้ายยิ่งกว่าโรค วางคลาสเหล่านี้ไว้ในที่ที่เหมาะสมและปรับโครงสร้างใหม่อย่างจริงจัง อย่าตั้งชื่อคลาส แพ็คเกจ หรือไลบรารีที่กว้างเกินไป เช่น "MiscUtils" หรือ "ExtrasLibrary" สิ่งนี้สนับสนุนให้ทิ้งโค้ดที่ไม่เกี่ยวข้องที่นั่น
การจัดรูปแบบมีความสำคัญน้อยกว่าที่โปรแกรมเมอร์ส่วนใหญ่คิดไว้มาก ความสม่ำเสมอแสดงให้เห็นว่าคุณใส่ใจในงานฝีมือของคุณและช่วยให้ผู้อื่นอ่านหนังสือได้หรือไม่? อย่างแน่นอน. แต่อย่าเสียเวลาสักวันในการเว้นวรรคหากบล็อกเพื่อให้ "ตรงกัน"
หากคุณต้องการคู่มือการจัดรูปแบบโค้ดจริงๆ ฉันขอแนะนำคู่มือ Java Style ของ Google เป็นอย่างยิ่ง ส่วนที่ดีที่สุดของคู่มือนั้นคือส่วนแนวทางปฏิบัติในการเขียนโปรแกรม คุ้มค่ากับการอ่านอย่างแน่นอน
การจัดทำเอกสารโค้ดที่ผู้ใช้เผชิญเป็นสิ่งสำคัญ และนี่หมายถึงการใช้ตัวอย่างและใช้คำอธิบายที่สมเหตุสมผลของตัวแปร วิธีการ และคลาส
ผลที่ตามมาคือการไม่บันทึกสิ่งที่ไม่จำเป็นต้องจัดทำเป็นเอกสาร หากคุณไม่มีอะไรจะพูดเกี่ยวกับสิ่งที่เป็นข้อโต้แย้ง หรือหากชัดเจน ก็อย่าบันทึกไว้ เอกสาร Boilerplate นั้นแย่กว่าไม่มีเอกสารเลย เนื่องจากเป็นการหลอกผู้ใช้ให้คิดว่ามีเอกสารประกอบ
Java 8 มีสตรีมที่ดีและไวยากรณ์แลมบ์ดา คุณสามารถเขียนโค้ดดังนี้:
final List < String > filtered = list . stream ()
. filter ( s -> s . startsWith ( "s" ))
. map ( s -> s . toUpperCase ())
. collect ( Collectors . toList ());
แทนสิ่งนี้:
final List < String > filtered = new ArrayList <>();
for ( String str : list ) {
if ( str . startsWith ( "s" ) {
filtered . add ( str . toUpperCase ());
}
}
สิ่งนี้ทำให้คุณสามารถเขียนโค้ดได้คล่องมากขึ้น ซึ่งสามารถอ่านได้ง่ายขึ้น
การปรับใช้ Java อย่างถูกต้องอาจเป็นเรื่องยุ่งยากเล็กน้อย มีสองวิธีหลักในการปรับใช้ Java ในปัจจุบัน: ใช้เฟรมเวิร์กหรือใช้โซลูชันที่ปลูกเองซึ่งมีความยืดหยุ่นมากกว่า
เนื่องจากการปรับใช้ Java ไม่ใช่เรื่องง่าย จึงได้มีการสร้างเฟรมเวิร์กขึ้นมาเพื่อช่วยได้ สองสิ่งที่ดีที่สุดคือ Dropwizard และ Spring Boot กรอบงาน Play ยังถือเป็นหนึ่งในกรอบงานการปรับใช้เหล่านี้ได้เช่นกัน
พวกเขาทั้งหมดพยายามลดอุปสรรคในการนำโค้ดของคุณออกไป สิ่งเหล่านี้มีประโยชน์อย่างยิ่งหากคุณยังใหม่กับ Java หรือหากคุณต้องการทำงานให้เสร็จสิ้นอย่างรวดเร็ว การใช้งาน JAR เดี่ยวนั้นง่ายกว่าการปรับใช้ WAR หรือ EAR ที่ซับซ้อน
อย่างไรก็ตาม สิ่งเหล่านี้อาจไม่ยืดหยุ่นและค่อนข้างดื้อรั้น ดังนั้น หากโปรเจ็กต์ของคุณไม่สอดคล้องกับตัวเลือกที่ผู้พัฒนาเฟรมเวิร์กของคุณสร้างขึ้น คุณจะต้องย้ายไปยังการกำหนดค่าที่ดำเนินการด้วยตนเองมากขึ้น
ทางเลือกที่ดี : Gradle
Maven ยังคงเป็นเครื่องมือมาตรฐานในการสร้าง จัดทำแพ็คเกจ และรันการทดสอบของคุณ มีทางเลือกอื่นเช่น Gradle แต่ไม่มีการนำไปใช้แบบเดียวกับที่ Maven มี หากคุณยังใหม่กับ Maven คุณควรเริ่มต้นด้วย Maven ตามตัวอย่าง
ฉันชอบที่จะมีรูท POM ที่มีการพึ่งพาภายนอกทั้งหมดที่คุณต้องการใช้ มันจะมีลักษณะเช่นนี้ POM รูทนี้มีการขึ้นต่อกันภายนอกเพียงครั้งเดียว แต่หากผลิตภัณฑ์ของคุณมีขนาดใหญ่พอ คุณจะมีหลายสิบรายการ POM รูทของคุณควรเป็นโปรเจ็กต์ของตัวเอง: ในการควบคุมเวอร์ชันและรีลีสเหมือนกับโปรเจ็กต์ Java อื่นๆ
หากคุณคิดว่าการแท็ก POM รูทของคุณสำหรับการเปลี่ยนแปลงการขึ้นต่อกันภายนอกทุกครั้งนั้นมากเกินไป คุณไม่ต้องเสียเวลาหนึ่งสัปดาห์ในการติดตามข้อผิดพลาดการขึ้นต่อกันข้ามโปรเจ็กต์
โปรเจ็กต์ Maven ทั้งหมดของคุณจะมี POM รูทและข้อมูลเวอร์ชันทั้งหมด ด้วยวิธีนี้ คุณจะได้รับเวอร์ชันที่บริษัทของคุณเลือกไว้สำหรับการขึ้นต่อกันภายนอกแต่ละรายการ และปลั๊กอิน Maven ที่ถูกต้องทั้งหมด หากคุณต้องการดึงการพึ่งพาภายนอก มันจะทำงานในลักษณะนี้:
< dependencies >
< dependency >
< groupId >org.third.party</ groupId >
< artifactId >some-artifact</ artifactId >
</ dependency >
</ dependencies >
หากคุณต้องการการพึ่งพาภายใน สิ่งนั้นควรได้รับการจัดการโดยแต่ละโครงการ ส่วน. มิฉะนั้นจะเป็นการยากที่จะรักษาหมายเลขเวอร์ชันรูท POM ให้เหมาะสม
หนึ่งในส่วนที่ดีที่สุดเกี่ยวกับ Java คือไลบรารีบุคคลที่สามจำนวนมากที่ทำทุกอย่าง โดยพื้นฐานแล้ว API หรือชุดเครื่องมือทั้งหมดจะมี Java SDK และง่ายต่อการดึงเข้ากับ Maven
และไลบรารี Java เหล่านั้นเองก็ขึ้นอยู่กับเวอร์ชันเฉพาะของไลบรารีอื่น หากคุณดึงไลบรารี่เพียงพอ คุณจะพบข้อขัดแย้งของเวอร์ชัน กล่าวคือ บางอย่างเช่นนี้:
Foo library depends on Bar library v1.0
Widget library depends on Bar library v0.9
เวอร์ชันใดจะถูกดึงเข้าสู่โครงการของคุณ?
ด้วยปลั๊กอินการบรรจบกันการพึ่งพา Maven บิลด์จะเกิดข้อผิดพลาดหากการขึ้นต่อกันของคุณไม่ได้ใช้เวอร์ชันเดียวกัน จากนั้น คุณมีสองทางเลือกในการแก้ไขข้อขัดแย้ง:
ตัวเลือกที่จะเลือกขึ้นอยู่กับสถานการณ์ของคุณ: หากคุณต้องการติดตามเวอร์ชันของโปรเจ็กต์หนึ่ง ให้แยกออกก็สมเหตุสมผล ในทางกลับกัน หากคุณต้องการให้ชัดเจนเกี่ยวกับเรื่องนี้ คุณสามารถเลือกเวอร์ชันได้ แม้ว่าคุณจะต้องอัปเดตเมื่อคุณอัปเดตการอ้างอิงอื่นๆ ก็ตาม
แน่นอนว่าคุณต้องการเซิร์ฟเวอร์บูรณาการอย่างต่อเนื่องซึ่งจะสร้างเวอร์ชัน SNAPSHOT และการสร้างแท็กโดยใช้แท็ก git อย่างต่อเนื่อง
Jenkins และ Travis-CI เป็นตัวเลือกโดยธรรมชาติ
การครอบคลุมโค้ดมีประโยชน์ และ Cobertura มีปลั๊กอิน Maven และการสนับสนุน CI ที่ดี มีเครื่องมือครอบคลุมโค้ดอื่นๆ สำหรับ Java แต่ฉันเคยใช้ Cobertura
คุณต้องมีพื้นที่สำหรับใส่ JARs, WARs และ EARs ที่คุณสร้าง ดังนั้นคุณจะต้องมีพื้นที่เก็บข้อมูล
ตัวเลือกทั่วไปคือ Artifactory และ Nexus ทั้งสองทำงานและมีข้อดีและข้อเสียของตัวเอง
คุณควรมีการติดตั้ง Artifactory/Nexus ของคุณเองและสะท้อนการพึ่งพาของคุณไปยังมัน การดำเนินการนี้จะหยุดงานสร้างของคุณไม่ให้เสียหายเนื่องจากที่เก็บอัพสตรีม Maven บางส่วนหยุดทำงาน
ตอนนี้คุณได้คอมไพล์โค้ด ตั้งค่าพื้นที่เก็บข้อมูลแล้ว และคุณต้องนำโค้ดของคุณออกมาในสภาพแวดล้อมการพัฒนาและผลักดันมันไปสู่การใช้งานจริงในที่สุด อย่าละเลยที่นี่ เพราะการทำให้สิ่งนี้เป็นอัตโนมัติจะจ่ายเงินปันผลเป็นเวลานาน
Chef, Puppet และ Ansible เป็นตัวเลือกทั่วไป ฉันได้เขียนทางเลือกอื่นที่เรียกว่า Squadron ซึ่งแน่นอนว่าฉันคิดว่าคุณควรลองดูเพราะมันง่ายกว่าที่จะทำให้ถูกต้องมากกว่าทางเลือกอื่น
ไม่ว่าคุณจะเลือกเครื่องมือใด อย่าลืมทำให้การปรับใช้ของคุณเป็นแบบอัตโนมัติ
คุณลักษณะที่ดีที่สุดเกี่ยวกับ Java น่าจะเป็นจำนวนไลบรารีที่กว้างขวางที่มีอยู่ นี่คือคอลเล็กชั่นห้องสมุดเล็กๆ ที่อาจใช้ได้กับคนกลุ่มใหญ่ที่สุด
ไลบรารี่มาตรฐานของ Java ซึ่งครั้งหนึ่งเคยก้าวไปข้างหน้าอย่างน่าทึ่ง ตอนนี้ดูเหมือนว่าจะขาดคุณสมบัติที่สำคัญหลายประการ
โครงการ Apache Commons มีไลบรารีที่มีประโยชน์มากมาย
Commons Codec มีวิธีการเข้ารหัส/ถอดรหัสที่มีประโยชน์มากมายสำหรับสตริง Base64 และเลขฐานสิบหก อย่าเสียเวลาเขียนสิ่งเหล่านั้นใหม่
Commons Lang เป็นไลบรารี่สำหรับการจัดการและการสร้างสตริง ชุดอักขระ และวิธีอรรถประโยชน์เบ็ดเตล็ดอีกมากมาย
Commons IO มีวิธีการที่เกี่ยวข้องกับไฟล์ทั้งหมดที่คุณต้องการ มันมี FileUtils.copyDirectory, FileUtils.writeStringToFile, IOUtils.readLines และอีกมากมาย
Guava เป็นห้องสมุดที่ยอดเยี่ยมของ Google ที่นี่ซึ่งขาดหายไปจาก Java แทบจะกลั่นกรองทุกสิ่งที่ฉันชอบเกี่ยวกับห้องสมุดนี้ได้ยาก แต่ฉันจะพยายาม
แคช เป็นวิธีง่ายๆ ในการรับแคชในหน่วยความจำที่สามารถใช้เพื่อแคชการเข้าถึงเครือข่าย การเข้าถึงดิสก์ บันทึกฟังก์ชัน หรืออะไรก็ตามจริงๆ เพียงใช้ CacheBuilder ซึ่งจะบอก Guava ถึงวิธีสร้างแคชของคุณ เท่านี้ก็เรียบร้อย!
คอลเลก ชันที่ไม่เปลี่ยนรูป มีสิ่งเหล่านี้มากมาย: ImmutableMap, ImmutableList หรือแม้แต่ ImmutableSortedMultiSet หากนั่นคือสไตล์ของคุณ
ฉันชอบเขียนคอลเลกชันที่ไม่แน่นอนในแบบของ Guava ด้วย:
// Instead of
final Map < String , Widget > map = new HashMap <>();
// You can use
final Map < String , Widget > map = Maps . newHashMap ();
มีคลาสคงที่สำหรับรายการ แผนที่ ชุด และอื่นๆ สะอาดกว่าและอ่านง่ายกว่า
หากคุณติดอยู่กับ Java 6 หรือ 7 คุณสามารถใช้คลาส Collections2 ซึ่งมีวิธีการเช่นตัวกรองและการแปลง ช่วยให้คุณสามารถเขียนโค้ดได้อย่างคล่องแคล่วโดยไม่ต้องรองรับการสตรีมของ Java 8
Guava มีสิ่งง่ายๆ เช่นกัน เช่น Joiner ที่รวมสตริงบนตัวแยกและคลาสเพื่อจัดการกับการขัดจังหวะโดยไม่สนใจสิ่งเหล่านั้น
ไลบรารี Gson ของ Google เป็นไลบรารีการแยกวิเคราะห์ JSON ที่ง่ายและรวดเร็ว มันทำงานเช่นนี้:
final Gson gson = new Gson ();
final String json = gson . toJson ( fooWidget );
final FooWidget newFooWidget = gson . fromJson ( json , FooWidget . class );
มันง่ายมากและยินดีที่ได้ร่วมงานด้วย คู่มือผู้ใช้ Gson มีตัวอย่างอีกมากมาย
สิ่งที่ทำให้ฉันรำคาญกับ Java ก็คือมันไม่มีสิ่งอันดับในไลบรารีมาตรฐาน โชคดีที่โปรเจ็กต์ Java tuples แก้ไขสิ่งนั้นได้
ใช้งานง่ายและใช้งานได้ดี:
Pair < String , Integer > func ( String input ) {
// something...
return Pair . with ( stringResult , intResult );
}
Javaslang เป็นไลบรารีการทำงานที่ออกแบบมาเพื่อเพิ่มคุณสมบัติที่ขาดหายไปซึ่งควรเป็นส่วนหนึ่งของ Java 8 คุณสมบัติบางอย่างเหล่านี้คือ
มีไลบรารี Java หลายแห่งซึ่งขึ้นอยู่กับคอลเลกชัน Java ดั้งเดิม สิ่งเหล่านี้ถูกจำกัดให้เข้ากันได้กับคลาสที่สร้างขึ้นด้วยโฟกัสเชิงวัตถุและออกแบบให้ไม่แน่นอน คอลเลกชั่น Javaslang สำหรับ Java เป็นรูปแบบใหม่ที่ได้รับแรงบันดาลใจจาก Haskell, Clojure และ Scala สร้างขึ้นโดยเน้นการใช้งานและเป็นไปตามการออกแบบที่ไม่เปลี่ยนรูป
โค้ดเช่นนี้จะปลอดภัยสำหรับเธรดโดยอัตโนมัติและไม่มีการลองจับเลย:
// Success/Failure containing the result/exception
public static Try < User > getUser ( int userId ) {
return Try . of (() -> DB . findUser ( userId ))
. recover ( x -> Match . of ( x )
. whenType ( RemoteException . class ). then ( e -> ...)
. whenType ( SQLException . class ). then ( e -> ...));
}
// Thread-safe, reusable collections
public static List < String > sayByeBye () {
return List . of ( "bye, " bye ", "collect" , "mania" )
. map ( String :: toUpperCase )
. intersperse ( " " );
}
Joda-Time เป็นห้องสมุดเวลาที่ดีที่สุดที่ฉันเคยใช้ เรียบง่าย ตรงไปตรงมา ทดสอบได้ง่าย คุณสามารถขออะไรได้อีก?
คุณต้องการสิ่งนี้หากคุณยังไม่ได้ใช้ Java 8 เนื่องจากมีไลบรารีเวลาใหม่ของตัวเองที่ไม่ห่วย
ลอมบอกเป็นห้องสมุดที่น่าสนใจ ด้วยคำอธิบายประกอบ ช่วยให้คุณสามารถลดรูปแบบสำเร็จรูปที่ Java ต้องทนทุกข์ทรมานได้แย่มาก
ต้องการ setters และ getters สำหรับตัวแปรคลาสของคุณหรือไม่? เรียบง่าย:
public class Foo {
@ Getter @ Setter private int var ;
}
ตอนนี้คุณสามารถทำสิ่งนี้ได้:
final Foo foo = new Foo ();
foo . setVar ( 5 );
และยังมีอีกมากมาย ฉันยังไม่ได้ใช้ลอมบอกในการผลิตเลย แต่ฉันแทบรอไม่ไหวแล้ว
ทางเลือกที่ดี : Jersey หรือ Spark
มีสองค่ายหลักสำหรับการให้บริการเว็บ RESTful ใน Java: JAX-RS และทุกอย่างอื่น
JAX-RS เป็นวิธีดั้งเดิม คุณรวมคำอธิบายประกอบเข้ากับอินเทอร์เฟซและการใช้งานเพื่อสร้างบริการเว็บโดยใช้บางอย่างเช่น Jersey สิ่งที่ดีเกี่ยวกับเรื่องนี้ก็คือคุณสามารถสร้างลูกค้าจากคลาสอินเทอร์เฟซได้อย่างง่ายดาย
กรอบการทำงานของ Play เป็นบริการเว็บที่แตกต่างอย่างสิ้นเชิงบน JVM: คุณมีไฟล์เส้นทางแล้วคุณเขียนคลาสที่อ้างอิงในเส้นทางเหล่านั้น จริงๆ แล้วมันเป็นกรอบงาน MVC ทั้งหมด แต่คุณสามารถใช้กับบริการเว็บ REST ได้อย่างง่ายดาย
ใช้ได้กับทั้ง Java และ Scala แม้จะใช้งานแบบ Scala-first อยู่บ้าง แต่ก็ยังใช้งานได้ดีใน Java
หากคุณคุ้นเคยกับไมโครเฟรมเวิร์กอย่าง Flask ใน Python แล้ว Spark จะคุ้นเคยเป็นอย่างดี มันทำงานได้ดีเป็นพิเศษกับ Java 8
มีโซลูชันการบันทึก Java มากมายที่มีอยู่ สิ่งที่ฉันชอบคือ SLF4J เพราะมันเสียบปลั๊กได้ดีมากและสามารถรวมบันทึกจากเฟรมเวิร์กการบันทึกที่แตกต่างกันมากมายในเวลาเดียวกัน มีโปรเจ็กต์แปลก ๆ ที่ใช้ java.util.logging, JCL และ log4j หรือไม่? SLF4J เหมาะสำหรับคุณ
คู่มือสองหน้าเป็นสิ่งที่คุณต้องมีในการเริ่มต้น
ฉันไม่ชอบเฟรมเวิร์ก ORM หนัก ๆ เพราะฉันชอบ SQL ดังนั้นฉันจึงเขียนเทมเพลต JDBC จำนวนมาก และการบำรุงรักษาก็ค่อนข้างยาก jOOQ เป็นทางออกที่ดีกว่ามาก
มันช่วยให้คุณเขียน SQL ใน Java ด้วยวิธีที่ปลอดภัย:
// Typesafely execute the SQL statement directly with jOOQ
Result < Record3 < String , String , String >> result =
create . select ( BOOK . TITLE , AUTHOR . FIRST_NAME , AUTHOR . LAST_NAME )
. from ( BOOK )
. join ( AUTHOR )
. on ( BOOK . AUTHOR_ID . equal ( AUTHOR . ID ))
. where ( BOOK . PUBLISHED_IN . equal ( 1948 ))
. fetch ();
การใช้สิ่งนี้และรูปแบบ DAO จะทำให้การเข้าถึงฐานข้อมูลเป็นเรื่องง่าย
การทดสอบมีความสำคัญต่อซอฟต์แวร์ของคุณ แพ็คเกจเหล่านี้ช่วยให้ง่ายขึ้น
ทางเลือกที่ดี : TestNG
jUnit ไม่จำเป็นต้องมีการแนะนำ เป็นเครื่องมือมาตรฐานสำหรับการทดสอบหน่วยใน Java
แต่คุณอาจไม่ได้ใช้ jUnit อย่างเต็มประสิทธิภาพ jUnit รองรับการทดสอบแบบพาราเมตริก กฎที่ป้องกันไม่ให้คุณเขียนแบบสำเร็จรูปจำนวนมาก ทฤษฎีในการสุ่มทดสอบโค้ดบางอย่าง และสมมติฐาน
หากคุณได้ทำการ Dependency Inject เสร็จแล้ว นี่คือจุดที่คุณจะได้ประโยชน์: การเยาะเย้ยโค้ดที่มีผลข้างเคียง (เช่น การพูดคุยกับเซิร์ฟเวอร์ REST) และยังคงยืนยันพฤติกรรมของโค้ดที่เรียกใช้โค้ดนั้น
jMock เป็นเครื่องมือจำลองมาตรฐานสำหรับ Java ดูเหมือนว่านี้:
public class FooWidgetTest {
private Mockery context = new Mockery ();
@ Test
public void basicTest () {
final FooWidgetDependency dep = context . mock ( FooWidgetDependency . class );
context . checking ( new Expectations () {{
oneOf ( dep ). call ( with ( any ( String . class )));
atLeast ( 0 ). of ( dep ). optionalCall ();
}});
final FooWidget foo = new FooWidget ( dep );
Assert . assertTrue ( foo . doThing ());
context . assertIsSatisfied ();
}
}
นี่เป็นการตั้งค่า FooWidgetDependency ผ่าน jMock จากนั้นเพิ่มความคาดหวัง เราคาดว่าเมธอด การโทร ของ dep จะถูกเรียกหนึ่งครั้งด้วย String บางตัว และเมธอด optionCall ของ dep นั้นจะถูกเรียกว่าศูนย์ครั้งหรือมากกว่านั้น
หากคุณต้องตั้งค่าการขึ้นต่อกันแบบเดิมซ้ำแล้วซ้ำอีก คุณควรใส่สิ่งนั้นลงในฟิกซ์เจอร์ทดสอบและใส่ assertIsSatisfied ลงในฟิกซ์เจอร์ @After
คุณเคยทำเช่นนี้กับ jUnit หรือไม่?
final List < String > result = some . testMethod ();
assertEquals ( 4 , result . size ());
assertTrue ( result . contains ( "some result" ));
assertTrue ( result . contains ( "some other result" ));
assertFalse ( result . contains ( "shouldn't be here" ));
นี่เป็นเพียงตัวอย่างที่น่ารำคาญ AssertJ แก้ปัญหานี้ คุณสามารถแปลงรหัสเดียวกันเป็น:
assertThat ( some . testMethod ()). hasSize ( 4 )
. contains ( "some result" , "some other result" )
. doesNotContain ( "shouldn't be here" );
อินเทอร์เฟซที่คล่องแคล่วนี้ทำให้การทดสอบของคุณอ่านง่ายขึ้น คุณต้องการอะไรอีก?
ทางเลือกที่ดี : Eclipse และ Netbeans
Java IDE ที่ดีที่สุดคือ IntelliJ IDEA มันมีคุณสมบัติที่ยอดเยี่ยมมากมาย และเป็นสิ่งสำคัญจริงๆ ที่ทำให้การใช้ภาษา Java อย่างละเอียด การเติมข้อความอัตโนมัตินั้นยอดเยี่ยม การตรวจสอบก็ยอดเยี่ยม และเครื่องมือการปรับโครงสร้างใหม่ก็มีประโยชน์มาก
Community Edition แบบฟรีนั้นดีพอสำหรับฉัน แต่มีฟีเจอร์ดีๆ มากมายใน Ultimate Edition เช่น เครื่องมือฐานข้อมูล การรองรับ Spring Framework และ Chronon
หนึ่งในคุณสมบัติที่ฉันชื่นชอบของ GDB 7 คือความสามารถในการย้อนเวลากลับไปเมื่อทำการดีบั๊ก สิ่งนี้เป็นไปได้ด้วยปลั๊กอิน Chronon IntelliJ เมื่อคุณได้รับรุ่น Ultimate
คุณจะได้รับประวัติที่แปรผัน การย้อนกลับ ประวัติวิธีการ และอื่นๆ อีกมากมาย การใช้ครั้งแรกอาจดูแปลกเล็กน้อย แต่ก็สามารถช่วยแก้ไขจุดบกพร่องที่ซับซ้อนจริงๆ, Heisenbugs และอื่นๆ ที่คล้ายกันได้
ทางเลือกที่ดี : DCEVM
การบูรณาการอย่างต่อเนื่องมักเป็นเป้าหมายของผลิตภัณฑ์ซอฟต์แวร์ในฐานะบริการ จะเป็นอย่างไรหากคุณไม่จำเป็นต้องรอให้บิลด์เสร็จสิ้นเพื่อดูการเปลี่ยนแปลงโค้ดแบบเรียลไทม์ล่ะ
นั่นคือสิ่งที่ JRebel ทำ เมื่อคุณเชื่อมต่อเซิร์ฟเวอร์กับไคลเอนต์ JRebel คุณจะเห็นการเปลี่ยนแปลงบนเซิร์ฟเวอร์ของคุณได้ทันที ประหยัดเวลาได้มากเมื่อคุณต้องการทดสอบอย่างรวดเร็ว
ระบบประเภทของ Java ค่อนข้างอ่อนแอ มันไม่ได้แยกความแตกต่างระหว่าง Strings และ Strings ที่เป็นนิพจน์ทั่วไปจริงๆ และไม่ได้ทำการตรวจสอบมลทินใดๆ อย่างไรก็ตาม Checker Framework ทำหน้าที่นี้และอื่นๆ อีกมากมาย
ใช้คำอธิบายประกอบเช่น @Nullable เพื่อตรวจสอบประเภท คุณยังสามารถกำหนดคำอธิบายประกอบของคุณเองเพื่อทำให้การวิเคราะห์แบบคงที่มีประสิทธิภาพมากยิ่งขึ้น
แม้ว่าจะปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุด แม้แต่นักพัฒนาที่ดีที่สุดก็ยังทำผิดพลาดได้ มีเครื่องมือมากมายที่คุณสามารถใช้เพื่อตรวจสอบโค้ด Java ของคุณเพื่อตรวจหาปัญหาในโค้ดของคุณ ด้านล่างนี้คือเครื่องมือยอดนิยมบางส่วนที่ได้รับการคัดสรรบางส่วน สิ่งเหล่านี้จำนวนมากผสานรวมกับ IDE ยอดนิยม เช่น Eclipse หรือ IntelliJ ช่วยให้คุณมองเห็นข้อผิดพลาดในโค้ดของคุณเร็วขึ้น
นอกจากการใช้เครื่องมือเหล่านี้ในระหว่างการพัฒนาแล้ว ก็มักจะเป็นความคิดที่ดีที่จะให้เครื่องมือเหล่านี้ทำงานในระหว่างขั้นตอนการสร้างของคุณด้วย พวกเขาสามารถเชื่อมโยงกับเครื่องมือสร้างเช่น Maven หรือ Gradle และยังเป็นเครื่องมือบูรณาการอย่างต่อเนื่อง
หน่วยความจำรั่วเกิดขึ้นแม้ใน Java โชคดีที่มีเครื่องมือสำหรับสิ่งนั้น เครื่องมือที่ดีที่สุดที่ฉันเคยใช้เพื่อแก้ไขสิ่งเหล่านี้คือ Eclipse Memory Analyzer ใช้ฮีปดัมพ์และช่วยให้คุณค้นหาปัญหาได้
มีหลายวิธีในการรับฮีปดัมพ์สำหรับกระบวนการ JVM แต่ฉันใช้ jmap:
$ jmap -dump:live,format=b,file=heapdump.hprof -F 8152
Attaching to process ID 8152, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 23.25-b01
Dumping heap to heapdump.hprof ...
... snip ...
Heap dump file created
จากนั้น คุณสามารถเปิดไฟล์ heapdump.hprof ด้วย Memory Analyzer และดูว่าเกิดอะไรขึ้นอย่างรวดเร็ว
แหล่งข้อมูลที่จะช่วยให้คุณเป็นผู้เชี่ยวชาญ Java