Lợi ích của việc chuyển đổi trên Chuỗi trong Java 7 là gì?


19

Khi tôi bắt đầu lập trình bằng Java, thực tế là các câu lệnh chuyển đổi không làm tôi thất vọng. Sau đó, khi sử dụng Enums, tôi nhận ra những lợi ích mà bạn có được với chúng thay vì chuyển qua các giá trị thô - an toàn kiểu (mang lại khả năng tái cấu trúc dễ dàng hơn) & cũng rõ ràng cho các nhà phát triển khác.

Tôi đang đấu tranh để nghĩ về một tình huống trong đó với SE7 bây giờ tôi sẽ quyết định sử dụng một công tắc có chuỗi làm đầu vào thay vì Enums. Nếu chúng được thực hiện thông qua việc chuyển đổi trên toàn bộ chuỗi (ví dụ: thay vì khớp một phần hoặc regex), thì dường như không cung cấp ít lý do hơn để mã thay đổi.

Và với các công cụ IDE và tỷ lệ đọc-ghi của mã hóa, tôi sẽ tự động tạo ra một Enum bổ sung hơn nhiều so với việc chuyển xung quanh các giá trị chuỗi.

Họ mang lại lợi ích gì cho chúng ta khi là lập trình viên? Ít nồi hơi-tấm?

Nó không cảm thấy như ngôn ngữ đã khóc cho tính năng này. Mặc dù có thể có một trường hợp sử dụng tôi đang xem.


Các chuỗi đã được sử dụng rất nhiều trong các câu lệnh chuyển đổi, nhưng vì mọi người không thể sử dụng chúng trực tiếp nên họ đã sử dụng các cách giải quyết như người khổng lồ nếu cây khác hoặc chuyển đổi sang enum. Cả hai cách giải quyết làm cho mã ít đọc hơn. Cả hai cách đều là cách giải quyết và tại sao sử dụng cách giải quyết nếu một giải pháp được triển khai thực tế cho thấy ý định của các lập trình viên tốt hơn.
Pieter B

@PieterB Mặc dù có thể cho rằng, một Enum đang thêm giá trị ngữ nghĩa thay vì là một cách giải quyết, điều này mang lại sự an toàn về kiểu (ví dụ: một lỗi đánh máy sẽ bị bắt tại thời điểm biên dịch thay vì dẫn đến lỗi). Nó cũng cho phép chúng ta cấu trúc lại tất cả các phiên bản của chuỗi, như được sử dụng trong ngữ cảnh đó , mà không ảnh hưởng đến các cách sử dụng khác của chuỗi đó (có thể xảy ra khá thường xuyên với các đối tượng miền.)
otherdave 18/11/13

Câu trả lời:


12

Theo như tôi có thể nói, câu hỏi đặt ra là tại sao việc bọc các hằng chuỗi String vào enum chưa được coi là đủ để đáp ứng nhu cầu của người dùng ngôn ngữ. Điều này đã được giải quyết trong đề xuất tính năng chính thức được công bố tại danh sách gửi thư của JDK 7 (dự án Coin).

Theo tôi đọc đề xuất, thay thế sử dụng enums đã bị loại bỏ trên cơ sở rằng nó giới thiệu các loại phình to. Để thuận tiện cho bạn, phần có liên quan của đề xuất được trích dẫn bên dưới, với câu lệnh ghi địa chỉ được trích dẫn in đậm :

ƯU ĐIỂM CHÍNH: Điều gì làm cho đề xuất thay đổi thuận lợi?

Các mẫu mã hóa thông thường hơn có thể được sử dụng cho các hoạt động được chọn trên cơ sở một tập hợp các giá trị chuỗi không đổi; ý nghĩa của cấu trúc mới sẽ rõ ràng đối với các nhà phát triển Java.

LỢI ÍCH CHÍNH: Tại sao nền tảng tốt hơn nếu đề xuất được thông qua?

Hiệu suất tiềm năng tốt hơn cho mã công văn dựa trên chuỗi.

BỆNH NHÂN CHÍNH: Luôn có một chi phí.

Một số tăng độ thực thi và kiểm tra độ phức tạp cho trình biên dịch.

THAY ĐỔI: Những lợi ích và lợi thế có thể có cách nào đó mà không thay đổi ngôn ngữ?

Không; Các chuỗi kiểm tra if-then-other khác cho tính bằng chuỗi có thể rất tốn kém và giới thiệu một enum cho các hằng số có thể chuyển đổi của nó, một giá trị trên mỗi chuỗi giá trị, sẽ thêm một loại khác vào chương trình mà không có lý do chính đáng ...


phần táo bạo khá đáng ngạc nhiên
Simon Bergot

1
Đối với cá nhân tôi, đối với cá nhân tôi, nó đọc như một cách đối xử gián tiếp, "chúng tôi sẽ giảm cạnh tranh với C # nếu chúng tôi tiếp tục gắn bó với các cách xử lý trước Java5 với các cân nhắc như thế". :) Để biết ví dụ về "các cách trước Java5", hãy tham khảo JDK-1223179: bật chuỗi - gửi vào năm 1995 và nhanh chóng đóng lại khi không sửa : "Đừng nín thở. Không có gì giống với kế hoạch của chúng tôi . "
gnat

Cảm ơn, rất thú vị để xem lý do đưa ra trong đề xuất. Vẫn cảm thấy sai khi nói rằng chúng tôi đang giới thiệu một loại chương trình "không có lý do chính đáng" - chúng tôi là lập trình viên OO! :)
otherdave 18/11/13

5
@anotherdave "hướng đối tượng" biện minh cho việc giới thiệu các loại chỉ khi chúng phục vụ mục đích có ý nghĩa. Rõ ràng, ý kiến ​​phổ biến tại JCP đã chỉ ra rằng việc sử dụng enum làm trình bao bọc không có não cho các hằng chuỗi trong chuyển đổi không đủ điều kiện là có ý nghĩa
gnat

1
Ồ, tôi rất ngạc nhiên (một cách tốt) khi thấy đề xuất chính thức chủ động chống lại sự phình to kiểu. Điều đó thật mới mẻ. Kiểu phình là một vấn đề lớn trong Java.
Ben Lee

7

Ngoài việc làm cho mã dễ đọc hơn, còn có hiệu suất tăng tiềm năng so với if/else ifso sánh. Việc thay đổi có đáng hay không phụ thuộc vào số lần so sánh bạn sẽ thực hiện. Một chuyển đổi chuỗi sẽ được phát ra như hai hướng dẫn chuyển đổi riêng biệt. Đầu tiên hoạt động trên mã băm, vì vậy nó có xu hướng phức tạp lookupswitch, cuối cùng mang lại O(log n)sự phức tạp. Thứ hai luôn luôn là một sự hoàn hảo O(1) tableswitch, vì vậy sự phức tạp kết hợp vẫn còn O(log n). Một chuỗi các if/else ifcâu lệnh đơn tuyến tính sẽ cho O(n)độ phức tạp kém hơn một chút .

Nếu bạn đang so sánh nhiều hơn, giả sử, ba chuỗi, thì một chuỗi switchcó lẽ dễ đọc và gọn hơn. Nó có thể sẽ hoạt động tốt hơn, mặc dù bạn khó có thể nhận thấy sự khác biệt trừ khi bạn đang thực hiện một số lượng lớn các so sánh trên một đường dẫn mã nóng.


1
Tôi đã hỏi nhiều hơn mặc dù tại sao tôi lại sử dụng một công tắc trên một chuỗi chứ không phải là một công tắc trên một enum. Tôi sẽ xem xét một if/elsekhối lớn thực hành xấu, nhưng hiện tại, tôi sẽ không có nhiều lý do để sử dụng nó.
một

Nhưng sau đó, một Bản đồ kết hợp với mẫu lệnh thậm chí sẽ mang lại khả năng đọc dễ dàng hơn với cùng độ phức tạp vì bạn có loại lệnh bổ sung
SpaceTrucker

3

Chuyển đổi chuỗi có thể được sử dụng khi enumgiá trị của bạn đến từ bên ngoài, tức là được lưu trữ trong cơ sở dữ liệu.

Một điều đáng chú ý khác trong JDK 7 switchlà nó hoàn hảo hơn nhiều so với các if-elsecấu trúc.

Và một trường hợp sử dụng tuyệt vời cho switches chuỗi tốc độ có thể là phân tích cú pháp luồng JSON / XML khi bạn cần thực hiện nhiều chuyển đổi trên các loại nút và thuộc tính. Tôi không thể nghĩ ra lựa chọn nào tốt hơn cho việc này.


1
"Chuyển đổi chuỗi là không thể thay thế khi giá trị enum của bạn đến từ bên ngoài, tức là được lưu trữ trong cơ sở dữ liệu.": Bạn có thể giải thích về điều này không? Các chuỗi trong câu lệnh chuyển đổi được mã hóa cứng: ngay khi các chuỗi trong cơ sở dữ liệu bị thay đổi, mã của bạn đã hết hạn.
Giorgio

Vâng, bạn đã đúng - enumcó thể được sử dụng trong trường hợp này vì tính chất tĩnh của Java. Khi tôi viết bài này, tôi đã nghĩ về một Rolethư viện bảo mật thường được cung cấp dưới dạng một lớp và không thể đưa vào enum. Một trường hợp khác là mã Java / Groovy được biên dịch động - trong tình huống này, tuy nhiên rất hiếm, các chuyển đổi chuỗi có thể là một lựa chọn tốt hơn.
Andrey Chaschev

2

Sự đơn giản

Chuỗi trong hỗ trợ Switch rất hữu ích để xử lý dữ liệu mà không cần chuyển đổi sang enum hoặc if-elselogic. Đôi khi chỉ dễ dàng hơn để bật String.

Từ đề xuất tính năng tại danh sách gửi thư JDK 7 (dự án Coin) ( câu trả lời @gnat )

giới thiệu một enum cho các hằng số có thể chuyển đổi của nó, một giá trị quan tâm trên mỗi chuỗi, sẽ thêm một loại khác vào một chương trình mà không có lý do chính đáng ...

Phiên bản if-Else

Điều này là ngắn, nhưng nhiều người if'skhó đọc. Và điều này là chậm.

if (color.equals("red")) {
    System.out.println("Color is Red");
} else if (color.equals("green")) {
    System.out.println("Color is Green");
} else {
    System.out.println("Color not found");
}

Phiên bản Enum

Enums cần phải được xác định, điều này là tốt, nhưng đôi khi không cần thiết.

enum Color {RED, GREEN}

Chế biến như bình thường

try {
    switch (Color.valueOf(color)) {
        case RED:
            System.out.println("Color is Red");
            break;
        case GREEN:
            System.out.println("Color is Green");
            break;
    }
} catch (IllegalArgumentException e) {
    System.out.println("Color not found");
}

JDK 7 - Chuỗi trong phiên bản Báo cáo chuyển đổi

Chúng tôi có thể xử lý mà không cần chuyển đổi và xác định các loại bổ sung.

switch (color) {
    case "red":
        System.out.println("Color is Red");
        break;
    case "green":
        System.out.println("Color is Green");
        break;
    default:
        System.out.println("Color not found");
}

7
Điều này không giải quyết câu hỏi, mặc dù: tại sao bạn sẽ sử dụng chuỗi thay vì enums ở đây?
Dave Newton

0

Hầu hết các cải tiến trong bất kỳ ngôn ngữ nào là để làm cho mã dễ đọc hơn. Tôi ủng hộ mã có thể đọc hơn ưa thích bất cứ ngày nào.

Bạn có thể không tin điều này nhưng hãy thử:

public enum JettStaff {
  ADRIAN("Adrian German") {
    public String toString() {
      return name + " (dgerman@indiana.edu)";
    }
  },
  ARJIT("Arjit Sengupta") {
    public String toString() {
      return name + " (asengupt@indiana.edu)";
    }
  },

  // and on for the rest...

  private String name;

  public JettStaff(String n) { this.name = n; }
}

JettStaff x = JettStaff.SUZANNE;
System.out.println(x);

Tôi không rõ về ví dụ mã của bạn so với nhận xét của bạn ở trên. Ý bạn là Enum là một ví dụ về thứ gì đó khó đọc?
một


2
Điều này rất giả tạo; bạn đang giả vờ rằng enum sẽ không có trường email hoặc đây sẽ không phải là một lớp.
Dave Newton

4
@ user2860598 Nếu bạn đang cố gắng đưa ra quan điểm, hãy sử dụng một ví dụ có liên quan. Nó cũng không giải quyết vấn đề liên quan đến chất béo.
Dave Newton

1
@ user2860598 Câu trả lời bạn liên kết là nói rằng đã được giới thiệu & trước đây chúng có thể được "xấp xỉ" với một Enum. Quan điểm của tôi là việc sử dụng Enum dường như vẫn thích hợp hơn, ngay cả với phần giới thiệu của họ.
một

0

Enums rất tuyệt và bạn nên sử dụng chúng thay vì String khi bạn có khả năng làm điều đó. Nhưng có một số thời điểm bạn không thể, ví dụ như khi bạn cần làm việc với một số đối tượng bên ngoài đến từ bên ngoài Java. Hãy tưởng tượng rằng bạn phải phân tích một cái gì đó. Giống như phản hồi của máy chủ, cấu hình, tệp nhật ký hoặc một cái gì đó tương tự: bạn có một loạt các tùy chọn mà bạn đang tìm kiếm và không có cách nào chúng có thể được liệt kê. Vì vậy, trong Java <7, bạn sẽ bị mắc kẹt với một loạt các

  if (something.equals("foo")) {
    // foo processing
  } else 
  if (something.equals("bar")) {
   // bar processing
  }

Bạn vẫn có thể sử dụng enum trong trường hợp này bằng cách chỉ cố gắng lấy chúng theo tên và / hoặc bằng cách cung cấp chuỗi tùy chỉnh-> Enum nhưng đôi khi không thể hoặc chỉ không thực tế (nghĩa là khi bạn phải tạo quá nhiều enum)

TLDR : bạn hoàn toàn nên sử dụng Enums khi bạn đang làm việc hoàn toàn với mã Java nhưng không phải lúc nào cũng có thể với các đối tượng bên ngoài. Tôi hy vọng lời giải thích của tôi có ý nghĩa.


Nếu bạn đang xử lý dữ liệu bên ngoài và bạn đã biết đủ để biết những gì bạn cần trong các ifbáo cáo của mình , thì dù sao bạn cũng nên gói nó lại , điều đó có nghĩa là bạn vẫn có thể sử dụng enums hoặc mẫu lệnh, v.v.
Dave Newton

@DaveNewton có, bạn vẫn có thể sử dụng enums nhưng như tôi đã nói trong câu trả lời của tôi, đôi khi nó không thực tế như trong trường hợp cuối cùng bạn tạo ra một số enum chỉ được sử dụng một lần trong mã của bạn trong quá trình phân tích cú pháp.

@dimoniy Nhưng nếu bạn phải tạo ra 100 giá trị Enum, điều đó có nghĩa là với một công tắc thay thế, bạn phải có 100 câu lệnh tình huống? Nếu có nhiều biến số, tôi chắc chắn thích loại an toàn của enum.
otherdave 16/11/13

0

Tôi không đồng ý với ý kiến ​​rằng đó là mã sạch hơn và dễ đọc hơn khi bạn sử dụng Stringstrong các câu lệnh chuyển đổi và nghĩ rằng đó là một thực tiễn lập trình tồi. Nếu bạn thay đổi giá trị mà bạn sử dụng để lưu trữ, bạn phải thay đổi nó mỗi lần chuyển đổi hoặc nếu xảy ra nếu không. Điều này là không tốt vì bạn đang đặt các giá trị được mã hóa cứng cho mỗi mã của mã. Bạn sẽ làm gì nếu một ngày nào đó bạn quyết định thay đổi một trong những giá trị được mã hóa cứng này? Tìm kiếm và thay thế mọi bản sao của nó?

Nếu bạn có một số giá trị được mã hóa cứng mà bạn thực hiện các câu lệnh if-otherif, sử dụng các giá trị nguyên thủy không đổi cho chúng sẽ tốt hơn nhiều so với Java 1.5 chỉ vì nó mang lại sự an toàn kiểu.

OK, sẽ có tình huống bạn sẽ nhận được các giá trị Chuỗi (từ Yêu cầu HTTP, tệp, v.v.) và chuyển đổi chúng thành các giá trị nguyên thủy là một nỗi đau. Nhưng Enums làm một công việc tốt ở điểm này. Bởi vì khi bạn muốn thay đổi giá trị bạn lưu trữ trong Enum, chỉ cần thay đổi nó khi bạn khai báo. Không cần phải thay đổi bất cứ điều gì khác trong mã của bạn. (Tất nhiên bạn cần thay đổi các giá trị được lưu trữ ở một nơi khác).

Của couse nếu bạn chỉ thực hiện một mã bẩn và lười biếng, nó hoàn hảo. Bạn không muốn liên quan đến việc viết nhiều mã Enum, nhưng trong một phần mềm phức tạp quy mô lớn sẽ giết chết bạn.


-1

Nếu bạn biết thông tin nào đến và nó chỉ có thể là 5 tiểu bang thì hãy sử dụng Enum. Tuy nhiên, nếu các trạng thái có thể có thể trên 9000 và bạn chỉ cần tìm 42, thì sử dụng một công tắc sẽ tốt hơn vì bạn không muốn gõ tất cả các trạng thái đó ra.

Một Enum có xu hướng được lựa chọn bởi hầu hết trong hầu hết các trường hợp trừ khi các trạng thái có thể không được biết hoặc có rất nhiều và bạn chỉ quan tâm đến một số ít.

Nhưng tại sao họ lại giới thiệu nó bây giờ? Đó chỉ là một sự thay đổi cho phép mã sạch hơn.

Trong 1,5 họ cũng cho phép bạn tạo các cơ quan tùy chỉnh cho Enums.


Nhưng bạn sẽ không chỉ gán 8958 giá trị có thể khác cho trạng thái Enum chứ?
otherdave 16/11/13

@anotherdave Đây là nơi defaultswitchdo thỏa thuận để chơi. Tôi không biết rằng bạn có thể có trạng thái mặc định Enum, trừ khi bạn tạo trạng thái mặc định nhưng sau đó mã này sẽ bị sai lệch trong khi switchsử dụng sạch hơn nhiều.

3
Có vẻ lạ khi nói rằng một UNKNOWNtrạng thái trên Enum là phình to, nhưng defaulttrường hợp trên một công tắc thì không.
một
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.