(Chuỗi) hoặc .toString ()?


89

Tôi có một phương thức với một Object otham số.

Trong phương pháp này, tôi biết chính xác có một Stringtrong "o" không phải là null. Không cần phải kiểm tra, hoặc làm điều gì đó khác. Tôi phải đối xử với nó chính xác như một Stringđồ vật.

Chỉ tò mò - cái gì rẻ hơn - chuyển nó sang String, hay sử dụng Object.toString()? Hay nó giống nhau theo thời gian- / cpu- / mem- price?

Cập nhật: Phương thức chấp nhận Objectvì đó là việc triển khai một giao diện. Không có cách nào để thay đổi kiểu tham số.

Và hoàn toàn không thể null. Tôi chỉ muốn nói rằng tôi không cần phải kiểm tra xem nó có rỗng hay không. Trong trường hợp của tôi, luôn có một chuỗi trống.


1
Trong thế giới .NET, chúng tôi đã đo lường nó và ToString () nhanh hơn. Với lý do tại sao điều này là như vậy, điều này gần như chắc chắn đúng với một JVM lắp ráp.
Joshua

Câu trả lời:


72

truyền tới một Chuỗi rẻ hơn vì điều đó không yêu cầu lệnh gọi hàm bên ngoài, chỉ cần kiểm tra kiểu nội bộ.


4
Bạn đã thử nghiệm nó trên nhiều JRE chưa? Tôi đã thấy kết quả đáng ngạc nhiên cho tình huống này trong .NET. Thực tế, tôi nghi ngờ rằng hiệu suất sẽ quan trọng trong cuộc sống thực - nhưng đúc tốt hơn từ góc độ mã hóa phòng thủ.
Jon Skeet

Lời gọi phương thức sẽ được nội tuyến. Tốt nhất là sử dụng generic để loại bỏ dàn diễn viên (rõ ràng).
Tom Hawtin - tắc bóng vào

@Jon Skeet: Tôi đồng ý rằng sự khác biệt về hiệu suất sẽ không nhiều. @Tom Hawtin: Vì loại đối tượng sẽ được nhận không được biết tại thời điểm biên dịch, tôi không thể biết cách gọi phương thức có thể được nội tuyến. Bạn có thể làm rõ không?
euphoria83

@ euphoria83: Được tạo bởi trình biên dịch JIT, không phải bởi javac.
Michael Myers

Trên thực tế, không, phương thức không thể được nội tuyến. Loại chỉ được biết đến là Đối tượng và việc triển khai thực tế phụ thuộc vào loại thời gian chạy. Cái nào nhanh hơn vẫn còn phụ thuộc vào việc triển khai, nhưng theo tôi nhớ (tôi thực sự đã kiểm tra nó với microbenchmark tại một thời điểm), quá trình truyền dường như nhanh hơn. Đây không phải là một câu trả lời hiển nhiên: kiểm tra kiểu không phải lúc nào cũng nhanh hơn. Đối với kiểu Chuỗi, nó có thể là một đối tượng (không phải giao diện) và cuối cùng là đối tượng.
StaxMan

45

Tôi sẽ sử dụng một dàn diễn viên. Điều đó xác nhận "kiến thức" của bạn rằng đó là một chuỗi. Nếu vì bất cứ lý do gì mà bạn gặp phải lỗi và ai đó chuyển vào thứ gì đó không phải là một chuỗi, tôi nghĩ tốt hơn là bạn nên ném một ngoại lệ (mà một phép ép kiểu sẽ làm) hơn là tiếp tục thực thi với dữ liệu bị lỗi.



7

Nếu bạn biết Đối tượng o là một Chuỗi, tôi muốn nói chỉ cần truyền nó thành một Chuỗi và thực thi nó theo cách đó. Việc gọi toString () trên một đối tượng mà bạn biết chắc chắn là một Chuỗi có thể chỉ thêm sự nhầm lẫn.

Nếu Đối tượng o có thể là bất kỳ thứ gì khác ngoài Chuỗi, bạn sẽ cần gọi toString ().


Đây là câu trả lời chính xác cho tôi. Tại sao? Vì ép kiểu (string)Registry.GetValue...ném ra một ngoại lệ cho việc cố gắng ép một đối tượng Int32, ngược lại, nó Registry.GetValue...ToString()hoạt động như mong đợi.
trọng lực

3

Tôi sẽ không quá lo lắng về hiệu suất, nếu thao tác này được thực hiện thậm chí chỉ vài nghìn lần một giây - không có sự khác biệt rõ ràng.

Tuy nhiên, tôi sẽ lo ngại về việc "biết" đầu vào. Bạn có một phương thức chấp nhận một Objectvà bạn nên xử lý nó như vậy, tức là bạn không nên biết bất cứ điều gì về tham số, ngoại trừ việc nó tuân theo Objectgiao diện, điều này xảy ra với một toString()phương thức. Trong trường hợp này, tôi thực sự khuyên bạn nên sử dụng phương pháp đó thay vì chỉ giả định bất cứ điều gì.

OTOH, nếu đầu vào luônStringhoặc null, chỉ cần thay đổi phương thức để chấp nhận Strings và kiểm tra rõ ràng cho nulls (bất cứ lúc nào bạn nên làm bất cứ khi nào xử lý các trường hợp không phải là nguyên thủy ...)


Tôi đã nói rằng câu hỏi của tôi không có ý nghĩa đáng giá :) Tôi chỉ tò mò về lý thuyết cái gì rẻ hơn. Nhưng thanx dù sao
Vugluskr Ngày

Chi phí sẽ phụ thuộc vào mức độ hiệu quả của máy ảo khi gọi phương thức ảo so với kiểm tra kiểu. Đó là triển khai cụ thể.
Jon Skeet

2

Cho rằng kiểu tham chiếu là một Đối tượng và tất cả các Đối tượng có toString () chỉ cần gọi object.toString (). String.toString () chỉ trả về giá trị này.

  • toString () là loại mã ít hơn.
  • toString () ít mã byte hơn.
  • ép kiểu là một hoạt động tốn kém VS một cuộc gọi đa hình.
  • dàn diễn viên có thể thất bại.
  • Sử dụng String.valueOf (đối tượng) chỉ gọi object.toString () nếu nó không null.

1

Nếu những gì bạn có trong "o" là một Chuỗi thì không có nhiều sự khác biệt (có khả năng ép kiểu nhanh hơn, nhưng đó là một thứ triển khai VM / Thư viện).

Nếu "o" có thể không phải là một Chuỗi nhưng nó được cho là một Chuỗi thì việc ép kiểu là những gì bạn muốn (nhưng bạn nên đặt phương thức lấy một Chuỗi thay vì một Đối tượng).

Nếu "o" có thể là bất kỳ kiểu nào thì bạn phải sử dụng toString - nhưng hãy nhớ kiểm tra null trước.

void foo(final Object o)
{
    final String str;

    // without this you would get a class cast exception
    // be wary of using instanceof though - it is usually the wrong thing to do
    if(o instanceof String)
    {
        str = (String)o;
    }    
}

hoặc là

void foo(final Object o)
{
    final String str;

    // if you are 100% sure that o is not null then you can get rid of the else
    if(o != null)
    {
        str = o.toString();
    }
}

Tôi muốn viết mã cuối cùng là:

void foo(final Object o)
{
    final String str;

    if(o == null)
    {
        throw new IllegalArgumentException("o cannot be null");
    }

    str = o.toString();
}

2 đoạn mã đầu tiên sẽ không thực sự biên dịch ( finalbiến có thể chưa được khởi tạo). Bạn cần một elsecái mà sẽ ném ra một ngoại lệ hoặc khởi tạo strcho một cái gì đó.
Bruno Reis,

1

Tôi thấy kỳ lạ là quá trình truyền chậm hơn so với tra cứu vtable được ngụ ý bởi lệnh gọi chuỗi.


1

Không được có 'chuỗi null trong o'. Nếu o là null, nó không chứa chuỗi null, nó chỉ là null. Chỉ cần kiểm tra o cho null trước. Nếu bạn truyền hoặc gọi ToString () trên null, bạn sẽ gặp sự cố.


2
Đúc null sẽ không sụp đổ. Nó thậm chí sẽ không ném NullPointerException, nó sẽ chỉ gọi null cho kiểu mới. :)
Bombe
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.