2012-02-07 19 views
21

Tôi luôn luôn có thói quen sử dụng if, else-if statement thay vì nhiều if statement.Tại sao chúng ta sử dụng nếu, nếu thay vì nhiều nếu khối nếu cơ thể là một tuyên bố trở về

Ví dụ:

int val = -1; 
if (a == b1) { 
    return c1; 
} else if (a == b2) { 
    return c2; 
} ... 
... 
} else { 
    return c11; 
} 

như thế nào so sánh với ví dụ 2:

if (a == b1) { 
    return c1; 
} 
if (a == b2) { 
    return c2; 
} 
.... 

if (a == b11) { 
    return c11; 
} 

Tôi biết chức năng khôn ngoan họ đều giống nhau. Nhưng liệu thực hành tốt nhất có nên làm nếu có, hay không? Nó được nuôi dưỡng bởi một trong những người bạn của tôi khi tôi chỉ ra rằng anh ta có thể cấu trúc mã cơ sở khác nhau để làm cho nó sạch hơn. Nó đã là một thói quen cho tôi từ lâu nhưng tôi chưa bao giờ hỏi tại sao.

+1

Ngôn ngữ nào bạn đang đề cập đến? Java hoặc C++? – Billjk

+0

đó là java cho tôi, nhưng tôi đã sử dụng nó cho cả C++ và Java cho dài ... – Lily

+3

Đó là một sự khác biệt đáng kể, bởi vì bạn có thể thực hiện 'operator ==' trong C++ để làm những điều khó chịu (side-effecty) cũng có ảnh hưởng đến tối ưu hóa ...). AFAICR này không hoạt động trong Java. – bitmask

Trả lời

46

if-elseif-else báo cáo ngừng so sánh ngay sau khi phát hiện thấy điều đó đúng. if-if-if thực hiện mọi so sánh. Đầu tiên là hiệu quả hơn.

Chỉnh sửa: Điều này được chỉ ra trong các nhận xét rằng bạn thực hiện return trong mỗi khối if. Trong những trường hợp này, hoặc trong trường hợp điều khiển sẽ rời khỏi phương thức (ngoại lệ), không có sự khác biệt giữa thực hiện nhiều câu lệnh if và thực hiện các câu lệnh if-elseif-else.

Tuy nhiên, cách tốt nhất là sử dụng if-elseif-else dù sao đi nữa. Giả sử bạn thay đổi mã của mình sao cho bạn không làm return trong mỗi khối if. Sau đó, để duy trì hiệu quả, bạn cũng phải thay đổi thành thành ngữ if-elseif-else. Có nó là if-elseif-else ngay từ đầu sẽ giúp bạn chỉnh sửa trong tương lai và rõ ràng hơn đối với những người đang đọc mã của bạn (chứng kiến ​​sự hiểu sai tôi vừa cung cấp cho bạn bằng cách thực hiện lướt qua mã của bạn!).

+7

Bài đăng ngụ ý rằng mỗi điều kiện có một 'trả về', do đó, việc thực hiện phương thức dừng lại sau khi một điều kiện thành công. –

+0

Không có trong ví dụ được hiển thị. – pmr

+0

Ah, đó là sự thật. – CanSpice

0

ifelse if khác với hai câu lệnh if liên tiếp. Trong lần đầu tiên, khi CPU lấy chi nhánh if đầu tiên, else if sẽ không được chọn. Trong hai câu lệnh if liên tiếp, ngay cả khi số if đầu tiên được chọn và được thực hiện, số if tiếp theo cũng sẽ được kiểm tra và thực hiện nếu điều kiện là đúng.

0

Tôi nghĩ rằng các đoạn mã này tương đương với một lý do đơn giản là bạn có nhiều câu lệnh return. Nếu bạn có một câu lệnh return, bạn sẽ sử dụng các cấu trúc else ở đây là không cần thiết.

0

So sánh của bạn dựa trên thực tế là phần thân của câu lệnh if trả về điều khiển từ phương thức. Nếu không, chức năng sẽ khác.

Trong trường hợp này, chúng thực hiện cùng chức năng. Sau này là dễ dàng hơn nhiều để đọc và hiểu theo ý kiến ​​của tôi và sẽ là sự lựa chọn của tôi để sử dụng.

0

Chúng có khả năng làm những việc khác nhau.

Nếu a bằng b1b2, bạn nhập hai khối if. Trong ví dụ đầu tiên, bạn chỉ nhập một. Tôi tưởng tượng ví dụ đầu tiên nhanh hơn vì trình biên dịch có thể phải kiểm tra từng điều kiện theo tuần tự vì các quy tắc so sánh nhất định có thể áp dụng cho đối tượng. Nó có thể có khả năng tối ưu hóa chúng ... nhưng nếu bạn chỉ muốn một cái được nhập vào, cách tiếp cận đầu tiên rõ ràng hơn, ít có khả năng dẫn đến sai lầm của nhà phát triển hoặc mã không hiệu quả, vì vậy tôi chắc chắn khuyên bạn nên.

6

KHÔNG có chức năng tương đương.

Cách duy nhất nó sẽ có chức năng tương đương là nếu bạn đã thực hiện câu lệnh "if" cho mỗi giá trị có thể có của một (ví dụ: mọi giá trị int có thể, như được định nghĩa trong giới hạn.h trong C; sử dụng INT_MIN và INT_MAX, hoặc tương đương trong Java).

Câu lệnh khác cho phép bạn bao trả mọi giá trị còn lại có thể mà không phải viết hàng triệu câu lệnh "if".

Ngoài ra, thực hành mã hóa tốt hơn nên sử dụng nếu ... khác nếu ... khác, giống như cách trong câu lệnh chuyển/trường hợp, trình biên dịch sẽ khiến bạn bị cảnh báo nếu bạn không cung cấp "mặc định "tuyên bố trường hợp. Điều này ngăn bạn xem các giá trị không hợp lệ trong chương trình của bạn. ví dụ:

double square_root(double x) { 
    if(x > 0.0f) { 
     return sqrt(x); 
    } else if(x == 0.0f) { 
     return x; 
    } else { 
     printf("INVALID VALUE: x must be greater than zero"); 
     return 0.0f; 
    } 
} 

Bạn có muốn nhập hàng triệu câu lệnh if cho từng giá trị có thể của x trong trường hợp này không? Doubt it :)

Chúc mừng!

+0

+1 để chỉ ra rằng chúng không tương đương về mặt chức năng. – Perception

+4

Nếu chúng ta có sự trở lại trong mỗi mã khóa nếu chúng tương đương nhau. Phần giá trị không hợp lệ không nằm trong một khối khác mà thay vào đó là mã bình thường sau mã cuối cùng. Hoàn toàn tương đương chức năng. Ngay cả khi không có câu lệnh return, chúng ta có thể nhận được mã tương đương về hàm ngoài việc chúng ta thực hiện một kiểm tra bổ sung cho mỗi if (mặc dù một trình biên dịch tốt có thể loại bỏ nó) – Voo

7

Còn trường hợp b1 == b2 thì sao? (Và nếu a == b1a == b2?)

Khi điều đó xảy ra, nói chung, hai khối mã sau đây có thể có hành vi khác nhau:

if (a == b1) { 
    /* do stuff here, and break out of the test */ 
} 
else if (a == b2) { 
    /* this block is never reached */ 
} 

và:

if (a == b1) { 
    /* do stuff here */ 
} 
if (a == b2) { 
    /* do this stuff, as well */ 
} 

Nếu bạn muốn phân định rõ ràng chức năng cho các trường hợp khác nhau, sử dụng if-else hoặc switch-case để thực hiện một thử nghiệm.

Nếu bạn muốn chức năng khác nhau cho nhiều trường hợp, sau đó sử dụng nhiều khối if làm các thử nghiệm riêng biệt.

Đó không phải là câu hỏi "thực tiễn tốt nhất" nhiều như xác định xem bạn có một thử nghiệm hay nhiều thử nghiệm hay không.

1

Tôi có xu hướng nghĩ rằng việc sử dụng else if sẽ dễ dàng hơn khi đối mặt với thay đổi mã. Nếu ai đó đã điều chỉnh luồng điều khiển của hàm và thay thế trả về bằng hiệu ứng phụ hoặc cuộc gọi hàm với try-catch, else-if sẽ không thành công nếu tất cả các điều kiện thực sự là độc quyền. Nó thực sự phụ thuộc nhiều vào mã chính xác mà bạn đang làm việc để đưa ra một phán đoán chung và bạn cần phải xem xét các sự cân bằng có thể có với ngắn gọn.

0

Câu trả lời của CanSpice là chính xác. Một xem xét bổ sung cho hiệu suất là để tìm ra điều kiện xảy ra thường xuyên nhất. Ví dụ: nếu a == b1 chỉ xảy ra 1% thời gian, thì bạn sẽ có được hiệu suất tốt hơn bằng cách kiểm tra trường hợp khác trước.

Gir Loves Tacos trả lời cũng tốt. Thực hành tốt nhất là đảm bảo bạn có tất cả các trường hợp được bảo hiểm.

1

Với các câu hỏi return trong mỗi chi nhánh if.

Trong mã của bạn, bạn có các câu hỏi return trong mỗi điều kiện. Khi bạn có một tình huống như thế này, có hai cách để viết điều này.Đầu tiên là làm thế nào bạn đã viết nó trong Ví dụ 1:

if (a == b1) { 
    return c1; 
} else if (a == b2) { 
    return c2; 
} else { 
    return c11; 
} 

các khác như sau:

if (a == b1) { 
    return c1; 
} 
if (a == b2) { 
    return c2; 
} 
return c11; // no if or else around this return statement 

Hai cách viết mã của bạn là giống hệt nhau.

Cách bạn viết mã của bạn trong ví dụ 2 sẽ không biên dịch trong C++ hoặc Java (và sẽ là hành vi không xác định trong C), vì trình biên dịch không biết rằng bạn đã bao gồm tất cả các giá trị có thể là a. nghĩ rằng có một đường dẫn mã thông qua hàm có thể đưa bạn đến phần cuối của hàm mà không trả về một giá trị trả lại.

if (a == b1) { 
    return c1; 
} 
if (a == b2) { 
    return c2; 
} 
... 
if (a == b11) { 
    return c11; 
} 
// what if you set a to some value c12? 

Nếu không có return báo cáo trong mỗi chi nhánh if.

Without return báo cáo trong từng ngành if, mã của bạn sẽ là chức năng giống hệt nhau chỉ khi những điều khoản sau đây là đúng:

  1. Bạn không đột biến giá trị của a trong bất kỳ if chi nhánh.
  2. == là một mối quan hệ tương đương (theo nghĩa toán học) và không có số nào trong số b1 qua số b11 thuộc cùng một lớp tương đương.
  3. == không có bất kỳ tác dụng phụ nào.

Để làm rõ hơn nữa về điểm # 2 (và cũng chỉ # 3):

  • == luôn luôn là một quan hệ tương đương trong C hoặc Java và không bao giờ có tác dụng phụ.
  • Trong các ngôn ngữ cho phép bạn ghi đè toán tử ==, chẳng hạn như C++, Ruby hoặc Scala, toán tử bị ghi đè == có thể không phải là mối quan hệ tương đương và có thể có tác dụng phụ. Chúng tôi chắc chắn hy vọng rằng bất cứ ai overrides các nhà điều hành == là lành mạnh, đủ để viết một mối quan hệ tương đương mà không có tác dụng phụ, nhưng không có bảo đảm.
  • Trong JavaScript và một số ngôn ngữ lập trình nhất định có quy tắc chuyển đổi loại lỏng lẻo, có các trường hợp được tích hợp vào ngôn ngữ mà == không chuyển tiếp hoặc không đối xứng. (Trong Javascript, === là một mối quan hệ tương đương.)

Về hiệu suất, ví dụ # 1 được đảm bảo không thực hiện bất kỳ so sánh nào sau khi so khớp. Nó có thể có khả năng cho trình biên dịch tối ưu hóa # 2 để bỏ qua các so sánh bổ sung, nhưng không chắc. Trong ví dụ sau, nó có thể không thể, và nếu các chuỗi dài, các so sánh thêm không phải là giá rẻ.

if (strcmp(str, "b1") == 0) { 
    ... 
} 
if (strcmp(str, "b2") == 0) { 
    ... 
} 
if (strcmp(str, "b3") == 0) { 
    ... 
} 
1

Tôi thích nếu có cấu trúc khác, vì sẽ dễ dàng đánh giá tất cả các trạng thái có thể có của vấn đề của bạn trong mọi biến thể cùng với công tắc.Đó là mạnh mẽ hơn tôi tìm và nhanh hơn để gỡ lỗi đặc biệt là khi bạn làm nhiều đánh giá Boolean trong một môi trường yếu, đánh máy như PHP, ví dụ tại sao elseif là xấu (phóng đại cho cuộc biểu tình):

if(a && (c == d)) 
{ 
} elseif (b && (!d || a)) 
{ 
} elseif (d == a && (b^2 > c)) 
{ 
} else { 
} 

Vấn đề này đã vượt ra ngoài 4^2 = 16 trạng thái boolean, chỉ đơn giản là để chứng minh các hiệu ứng gõ nhẹ làm cho mọi thứ trở nên tồi tệ hơn. Nó không phải là quá khó để tưởng tượng một biến nhà nước ba, ba vấn đề biến liên quan đến một loại if ab elseif bc cách.

Để tối ưu hóa cho trình biên dịch.

0

Điều này hoàn toàn phụ thuộc vào điều kiện bạn đang thử nghiệm. Trong ví dụ của bạn, nó sẽ làm cho không có sự khác biệt cuối cùng nhưng khi thực hành tốt nhất, nếu bạn muốn một trong các điều kiện để được cuối cùng được thực hiện sau đó bạn sử dụng tốt hơn nếu khác

if (x > 1) { 
    System.out.println("Hello!"); 
}else if (x < 1) { 
    System.out.println("Bye!"); 
} 

Cũng lưu ý rằng nếu điều kiện đầu tiên là TRUE ý chí thứ hai KHÔNG được kiểm tra ở tất cả nhưng nếu bạn sử dụng

if (x > 1) { 
    System.out.println("Hello!"); 
} 
if (x < 1) { 
    System.out.println("Bye!"); 
} 

Điều kiện thứ hai sẽ được kiểm tra ngay cả khi điều kiện đầu tiên là TRUE. Điều này có thể được giải quyết bởi trình tối ưu hóa cuối cùng nhưng theo như tôi biết nó hoạt động theo cách đó. Ngoài ra, cái đầu tiên là cái được viết và cư xử như thế này nên nó luôn là lựa chọn tốt nhất cho tôi trừ khi logic yêu cầu khác.

Các vấn đề liên quan