PMD
nói với tôiHiệu quả: chuyển đổi báo cáo trên nếu phát biểu
Một chuyển đổi với ít hơn 3 chi nhánh là không hiệu quả, sử dụng một câu lệnh if để thay thế.
Tại sao lại như vậy? Tại sao 3? Làm thế nào để họ xác định hiệu quả?
PMD
nói với tôiHiệu quả: chuyển đổi báo cáo trên nếu phát biểu
Một chuyển đổi với ít hơn 3 chi nhánh là không hiệu quả, sử dụng một câu lệnh if để thay thế.
Tại sao lại như vậy? Tại sao 3? Làm thế nào để họ xác định hiệu quả?
Vì câu lệnh switch
được biên dịch với hai hướng dẫn JVM đặc biệt là lookupswitch
và tableswitch
. Chúng rất hữu ích khi làm việc với nhiều trường hợp nhưng chúng gây ra chi phí khi bạn chỉ có một vài nhánh.
Thay vào đó, một tuyên bố if/else
được biên dịch thành các chuỗi je
jne
... thường nhanh hơn nhưng yêu cầu nhiều so sánh hơn khi được sử dụng trong một chuỗi chi nhánh dài.
Bạn có thể thấy sự khác biệt bằng cách nhìn vào mã byte, trong mọi trường hợp, tôi sẽ không lo lắng về những vấn đề này, nếu bất cứ điều gì có thể trở thành một vấn đề thì JIT sẽ chăm sóc nó.
ví dụ thực tiễn:
switch (i)
{
case 1: return "Foo";
case 2: return "Baz";
case 3: return "Bar";
default: return null;
}
được biên dịch vào:
L0
LINENUMBER 21 L0
ILOAD 1
TABLESWITCH
1: L1
2: L2
3: L3
default: L4
L1
LINENUMBER 23 L1
FRAME SAME
LDC "Foo"
ARETURN
L2
LINENUMBER 24 L2
FRAME SAME
LDC "Baz"
ARETURN
L3
LINENUMBER 25 L3
FRAME SAME
LDC "Bar"
ARETURN
L4
LINENUMBER 26 L4
FRAME SAME
ACONST_NULL
ARETURN
Trong khi
if (i == 1)
return "Foo";
else if (i == 2)
return "Baz";
else if (i == 3)
return "Bar";
else
return null;
được biên dịch vào
L0
LINENUMBER 21 L0
ILOAD 1
ICONST_1
IF_ICMPNE L1
L2
LINENUMBER 22 L2
LDC "Foo"
ARETURN
L1
LINENUMBER 23 L1
FRAME SAME
ILOAD 1
ICONST_2
IF_ICMPNE L3
L4
LINENUMBER 24 L4
LDC "Baz"
ARETURN
L3
LINENUMBER 25 L3
FRAME SAME
ILOAD 1
ICONST_3
IF_ICMPNE L5
L6
LINENUMBER 26 L6
LDC "Bar"
ARETURN
L5
LINENUMBER 28 L5
FRAME SAME
ACONST_NULL
ARETURN
Jack cảm ơn bạn. Đây là một câu trả lời tuyệt vời. Trên một mặt lưu ý, bạn đã sử dụng cái gì để xem các tệp '.class'? – JAM
Đó là một plugin cho Eclipse, nếu tôi nhớ chính xác nó phải là một: http://andrei.gmxhome.de/bytecode/index.html – Jack
@JAM: Tôi tin rằng bạn cũng có thể sử dụng [javap] (http: // docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/javap.html). – RanRag
Mặc dù có hiệu quả nhỏ khi sử dụng công tắc so với sử dụng câu lệnh if, những lợi ích đó sẽ không đáng kể trong hầu hết các trường hợp. Và bất kỳ máy quét mã nguồn nào có giá trị muối của nó sẽ nhận ra rằng micro-optimizations là thứ cấp để làm rõ mã.
Họ đang nói rằng một câu lệnh if đơn giản hơn để đọc và nhận ít dòng mã hơn lệnh chuyển đổi nếu công tắc ngắn gọn đáng kể.
Từ PMD website:
TooFewBranchesForASwitchStatement: báo cáo Chuyển được indended được sử dụng để hỗ trợ hành vi phân nhánh phức tạp. Việc sử dụng một công tắc chỉ trong một vài trường hợp là không đúng, vì các công tắc không dễ hiểu như các câu lệnh if-then. Trong những trường hợp này, sử dụng câu lệnh if-then để tăng khả năng đọc mã.
Tôi tin rằng nó có liên quan đến cách chuyển đổi và nếu/người khác biên dịch xuống.
Giả sử có 5 phép tính để xử lý câu lệnh chuyển đổi. Nói một câu lệnh if có hai phép tính. Ít hơn 3 tùy chọn trong chuyển đổi của bạn sẽ bằng 4 tính toán trong ifs so với 5 trong công tắc. Tuy nhiên, chi phí vẫn không đổi trong một switch, vì vậy nếu nó có 3 lựa chọn, ifs sẽ là 3 * 2 xử lý, so với 5 vẫn còn cho switch.
Lợi ích khi xem hàng triệu phép tính là vô cùng đáng kể. Đó là một vấn đề của "đây là cách tốt hơn để làm điều đó" hơn là bất cứ điều gì có thể ảnh hưởng đến bạn. Nó sẽ chỉ làm như vậy trên một cái gì đó mà chu kỳ trên chức năng đó hàng triệu lần trong một sự lặp lại khá.
Tại sao lại như vậy?
Trình tự khác nhau của hướng dẫn được sử dụng khi mã được biên dịch JIT biên dịch sang mã gốc. Một chuyển đổi được thực hiện bởi một chuỗi các lệnh gốc thực hiện một nhánh gián tiếp. (Trình tự thường tải một địa chỉ từ một bảng và sau đó các nhánh tới địa chỉ đó.) Một if/else được thực hiện như các lệnh đánh giá điều kiện (có thể là một lệnh so sánh) theo sau là một lệnh nhánh có điều kiện.
Vì sao 3?
Đây là một quan sát thực nghiệm, tôi giả sử dựa trên việc phân tích các hướng dẫn mã nguồn gốc được tạo và/hoặc điểm chuẩn. (Hoặc có thể không. Để hoàn toàn chắc chắn, bạn sẽ cần phải hỏi (các) tác giả về quy tắc PMD đó cách chúng bắt nguồn số đó.)
Làm cách nào để xác định hiệu quả?
Thời gian thực hiện để thực hiện hướng dẫn.
Cá nhân tôi gặp sự cố với quy tắc này ... hoặc chính xác hơn với thông báo. Tôi nghĩ rằng nó nên nói rằng một tuyên bố if/else
là đơn giản và dễ đọc hơn một switch với 2 trường hợp. Vấn đề hiệu quả là thứ yếu và có thể không liên quan.
PMD là gì? ? ? – jmort253
PMD quét mã nguồn Java và tìm kiếm các vấn đề tiềm ẩn như lỗi có thể, mã chết, mã tối ưu, biểu thức quá phức tạp và mã trùng lặp. (Di chuột qua các thẻ) – Chords
Nó cũng nên quét chính nó cho ngữ pháp. "Ít hơn" nên "ít hơn". :) – yshavit