ฉันกลัว varargs ฉันไม่รู้ว่าจะใช้มันเพื่ออะไร
นอกจากนี้ยังรู้สึกอันตรายที่จะให้ผู้คนผ่านการโต้แย้งได้มากเท่าที่ต้องการ
ตัวอย่างของบริบทที่จะเป็นสถานที่ที่ดีในการใช้เป็นอย่างไร
ฉันกลัว varargs ฉันไม่รู้ว่าจะใช้มันเพื่ออะไร
นอกจากนี้ยังรู้สึกอันตรายที่จะให้ผู้คนผ่านการโต้แย้งได้มากเท่าที่ต้องการ
ตัวอย่างของบริบทที่จะเป็นสถานที่ที่ดีในการใช้เป็นอย่างไร
คำตอบ:
Varargsมีประโยชน์สำหรับวิธีการใด ๆ ที่ตอบสนองความต้องการการจัดการกับจำนวนไม่แน่นอนของวัตถุ String.format
หนึ่งตัวอย่างที่ดีคือ สตริงรูปแบบสามารถยอมรับพารามิเตอร์จำนวนเท่าใดก็ได้ดังนั้นคุณต้องใช้กลไกในการส่งผ่านจำนวนวัตถุใด ๆ
String.format("This is an integer: %d", myInt);
String.format("This is an integer: %d and a string: %s", myInt, myString);
กฎง่ายๆคือ:
"ใช้ varargs สำหรับวิธีการใด ๆ (หรือตัวสร้าง) ที่ต้องการอาเรย์ของ T (ชนิดใดก็ได้ T อาจเป็น) เป็นอินพุต"
ที่จะทำให้การเรียกใช้วิธีการเหล่านี้ง่ายขึ้น (ไม่จำเป็นต้องทำnew T[]{...}
)
คุณสามารถขยายกฎนี้เพื่อรวมวิธีการที่มีList<T>
อาร์กิวเมนต์โดยมีข้อโต้แย้งว่ามีไว้สำหรับอินพุตเท่านั้น (เช่นรายการจะไม่ได้รับการแก้ไขโดยวิธีการ)
นอกจากนี้ฉันจะละเว้นจากการใช้งานf(Object... args)
เพราะพลาดไปสู่วิธีการเขียนโปรแกรมด้วย API ที่ไม่ชัดเจน
ในแง่ของตัวอย่างฉันได้ใช้มันในDesignGridLayoutซึ่งฉันสามารถเพิ่มหลายJComponent
s ในการโทรครั้งเดียว:
layout.row().grid(new JLabel("Label")).add(field1, field2, field3);
ในโค้ดข้างต้นเพิ่มวิธี () add(JComponent... components)
ถูกกำหนดให้เป็น
ในที่สุดการดำเนินการของวิธีการดังกล่าวจะต้องดูแลความจริงที่ว่ามันอาจจะถูกเรียกด้วย vararg ว่าง! หากคุณต้องการกำหนดอย่างน้อยหนึ่งอาร์กิวเมนต์คุณต้องใช้กลอุบายที่น่าเกลียดเช่น:
void f(T arg1, T... args) {...}
ฉันพิจารณาเคล็ดลับนี้น่าเกลียดเพราะการใช้วิธีการจะตรงไปตรงมาน้อยกว่ามีเพียงT... args
ในรายการอาร์กิวเมนต์ของ
ความหวังนี้ช่วยชี้แจงจุดเกี่ยวกับ varargs
if (args.length == 0) throw new RuntimeException("foo");
หรือไม่ (เนื่องจากผู้โทรละเมิดสัญญา)
void f(T arg1, T... args)
เช่นนี้จะทำให้แน่ใจได้ว่ามันจะไม่ถูกเรียกโดยไม่มีข้อโต้แย้งใด ๆ
ฉันใช้ varargs บ่อยครั้งเพื่อส่งออกไปยังล็อกเพื่อการดีบั๊ก
ค่อนข้างทุกคลาสในแอพของฉันมีเมธอด debugPrint ():
private void debugPrint(Object... msg) {
for (Object item : msg) System.out.print(item);
System.out.println();
}
จากนั้นภายในวิธีการเรียนฉันมีการโทรดังต่อไปนี้:
debugPrint("for assignment ", hwId, ", student ", studentId, ", question ",
serialNo, ", the grade is ", grade);
เมื่อฉันพอใจว่ารหัสของฉันใช้งานได้ฉันใส่ความคิดเห็นรหัสในวิธี debugPrint () เพื่อให้บันทึกจะไม่ประกอบด้วยข้อมูลที่ไม่เกี่ยวข้องและไม่ต้องการมากเกินไป ต่อมาถ้าฉันพบข้อผิดพลาดฉันเพิ่งยกเลิกการใส่รหัส debugPrint () และการเรียก debugPrint () ทั้งหมดของฉันถูกเปิดใช้งานอีกครั้ง
แน่นอนฉันสามารถหลีกเลี่ยง varargs ได้อย่างง่ายดายและทำสิ่งต่อไปนี้แทน:
private void debugPrint(String msg) {
System.out.println(msg);
}
debugPrint("for assignment " + hwId + ", student " + studentId + ", question "
+ serialNo + ", the grade is " + grade);
อย่างไรก็ตามในกรณีนี้เมื่อฉันแสดงความคิดเห็นรหัส debugPrint () เซิร์ฟเวอร์ยังคงมีปัญหาในการเชื่อมต่อตัวแปรทั้งหมดในทุกการเรียก debugPrint () ถึงแม้ว่าจะไม่มีสิ่งใดทำกับสตริงผลลัพธ์ อย่างไรก็ตามถ้าฉันใช้ varargs เซิร์ฟเวอร์จะต้องใส่ไว้ในอาร์เรย์ก่อนที่จะตระหนักว่าไม่จำเป็นต้องใช้ ประหยัดเวลาได้มาก
สามารถใช้ Varargs ได้เมื่อเราไม่แน่ใจเกี่ยวกับจำนวนอาร์กิวเมนต์ที่จะส่งผ่านในเมธอด มันสร้างอาร์เรย์ของพารามิเตอร์ของความยาวที่ไม่ระบุในพื้นหลังและพารามิเตอร์ดังกล่าวสามารถถือว่าเป็นอาร์เรย์ในรันไทม์
หากเรามีวิธีการที่มากเกินไปที่จะยอมรับจำนวนพารามิเตอร์ที่แตกต่างกันแล้วแทนที่จะโหลดมากเกินไปวิธีที่แตกต่างกันครั้งเราก็สามารถใช้แนวคิด varargs
นอกจากนี้เมื่อชนิดของพารามิเตอร์แตกต่างกันไปจากนั้นการใช้ "การทดสอบ Object ... " จะทำให้โค้ดง่ายขึ้นมาก
ตัวอย่างเช่น:
public int calculate(int...list) {
int sum = 0;
for (int item : list) {
sum += item;
}
return sum;
}
อาเรย์ของ int ชนิด (รายการ) จะถูกส่งผ่านทางอ้อมเป็นพารามิเตอร์และถือเป็นอาเรย์ในรหัส
เพื่อความเข้าใจที่ดีขึ้นไปตามลิงค์นี้ (มันช่วยฉันได้มากในการทำความเข้าใจแนวคิดนี้อย่างชัดเจน): http://www.javadb.com/using-varargs-in-java
PS: แม้ฉันกลัวที่จะใช้ varargs เมื่อฉันไม่ได้รู้เรื่องมัน แต่ตอนนี้ฉันชินแล้ว ตามที่มีการกล่าวไว้ว่า: "เรายึดมั่นในสิ่งที่รู้กลัวความไม่รู้จัก" ดังนั้นใช้มันให้มากที่สุดและคุณก็จะเริ่มชอบมัน :)
Varargs เป็นคุณสมบัติที่เพิ่มเข้ามาใน java เวอร์ชั่น 1.5
ทำไมต้องใช้สิ่งนี้?
มันทำงานอย่างไร
มันสร้างอาร์เรย์ที่มีข้อโต้แย้งที่กำหนดและส่งผ่านอาร์เรย์ไปยังวิธีการ
ตัวอย่าง:
public class Solution {
public static void main(String[] args) {
add(5,7);
add(5,7,9);
}
public static void add(int... s){
System.out.println(s.length);
int sum=0;
for(int num:s)
sum=sum+num;
System.out.println("sum is "+sum );
}
}
ผลผลิต:
2
ผลรวมคือ 12
3
ผลรวมคือ 21
ฉันมีความกลัวที่เกี่ยวข้องกับ varargs เช่นกัน:
หากผู้เรียกส่งผ่านอาร์เรย์ที่ชัดเจนไปยังเมธอด (ตรงข้ามกับหลายพารามิเตอร์) คุณจะได้รับการอ้างอิงที่แชร์ไปยังอาร์เรย์นั้น
หากคุณต้องการเก็บอาร์เรย์นี้ไว้ภายในคุณอาจต้องการโคลนก่อนเพื่อหลีกเลี่ยงการที่ผู้โทรสามารถเปลี่ยนแปลงได้ในภายหลัง
Object[] args = new Object[] { 1, 2, 3} ;
varArgMethod(args); // not varArgMethod(1,2,3);
args[2] = "something else"; // this could have unexpected side-effects
แม้ว่าสิ่งนี้จะไม่แตกต่างจากการส่งผ่านวัตถุชนิดใดที่สถานะอาจเปลี่ยนแปลงในภายหลังเนื่องจากอาร์เรย์มักจะ (ในกรณีของการโทรที่มีอาร์กิวเมนต์หลายตัวแทนที่จะเป็นอาร์เรย์) วัตถุใหม่ที่สร้างขึ้นโดยคอมไพเลอร์ภายในที่คุณสามารถปลอดภัยได้ ใช้นี้เป็นพฤติกรรมที่ไม่คาดคิดอย่างแน่นอน
ฉันใช้ varargs บ่อยครั้งสำหรับตัวสร้างที่สามารถใช้วัตถุตัวกรองบางประเภท ตัวอย่างเช่นส่วนใหญ่ของระบบของเราที่อิงตาม Hadoop ขึ้นอยู่กับ Mapper ที่จัดการการเรียงลำดับและการดีซีเรียลไลเซชันของรายการให้กับ JSON และใช้ตัวประมวลผลจำนวนหนึ่งที่แต่ละรายการใช้เนื้อหาและปรับเปลี่ยนและส่งคืนหรือคืน null ปฏิเสธ
ใน Java doc ของ Var-Args มันค่อนข้างชัดเจนว่าการใช้ var args:
http://docs.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
เกี่ยวกับการใช้งานมันบอกว่า:
"ดังนั้นเมื่อใดที่คุณควรใช้ varargs? ในฐานะลูกค้าคุณควรใช้ประโยชน์จากมันเมื่อใดก็ตามที่ API เสนอให้การใช้งานที่สำคัญใน API หลักรวมถึงการสะท้อนการจัดรูปแบบข้อความและสิ่งอำนวยความสะดวก printf ใหม่ในฐานะนักออกแบบ API เพียงเท่าที่ผลประโยชน์นั้นน่าสนใจอย่างแท้จริงเท่านั้นโดยทั่วไปคุณไม่ควรใช้วิธี varargs มากเกินไปมิฉะนั้นจะเป็นเรื่องยากสำหรับโปรแกรมเมอร์ที่จะรู้ว่าการเรียกใช้งานมากเกินนั้นจะถูกเรียกใช้อย่างไร "