(String) або .toString ()?


89

У мене є метод з Object oпараметром.

У цьому методі я точно знаю, що є String"o", яке не є нульовим. Не потрібно перевіряти або робити щось інше. Я повинен поводитися з нею точно як з Stringпредметом.

Просто цікаво - що дешевше - кинути Stringчи використати Object.toString()? Або це те саме за часом- / процесором / мемом- ціною?

Оновлення: метод приймається, Objectоскільки це реалізація інтерфейсу. Неможливо змінити тип параметра.

І цього не може бути nullзовсім. Я просто хотів сказати, що мені не потрібно перевіряти його на відсутність чи порожнечу. У моєму випадку завжди є непустий рядок.


1
У світі .NET ми його виміряли, і ToString () працює швидше. Враховуючи причину, чому це так, майже напевно це саме стосується і JVM, що хвилюється.
Джошуа

Відповіді:


72

приведення в рядок дешевше, оскільки для цього не потрібен зовнішній виклик функції, а лише внутрішня перевірка типу.


4
Ви тестували його на декількох JRE? Я бачив дивовижні результати щодо точності цієї ситуації в .NET. Реально я сумніваюся, що виступ матиме значення в реальному житті - але кастинг краще з точки зору оборонного кодування.
Джон Скіт,

Виклик методу повинен бути вбудованим. Використання дженериків для видалення (явного) складання буде найкращим.
Том Хоутін - таклін

@ Джон Скіт: Я згоден, що різниця в продуктивності не буде великою. @Tom Hawtin: Оскільки тип об'єкта, який буде отриманий, невідомий під час компіляції, я не бачу, як виклик методу може бути вбудований. Ви можете уточнити, будь ласка?
euphoria83

@ euphoria83: Підкреслено компілятором JIT, а не javac.
Майкл Майєрс

Насправді ні, метод не можна вбудувати. Відомо, що тип - це лише Object, а фактична реалізація залежить від типу виконання. Який з них швидший, все ще залежить від реалізації, але, наскільки я пам’ятаю (я насправді тестував це за допомогою microbenchmark в один момент), кастинг здається швидшим. Це не очевидна відповідь: перевірка типу не завжди швидша. Для типу String це може бути, оскільки це об'єкт (а не інтерфейс), і остаточний.
StaxMan

45

Я б використав гіпс. Це підтверджує ваше "знання", що це рядок. Якщо з якоїсь причини у вас трапляється помилка, і хтось передає щось інше, ніж рядок, я вважаю, що було б краще викинути виняток (що зробить привід), ніж продовжувати виконувати з помилковими даними.



7

Якщо ви знаєте, що Об'єкт o - це рядок, я б сказав, просто перекиньте його на рядок і застосуйте його таким чином. Виклик toString () для об'єкта, який ви точно знаєте як String, може просто внести плутанину.

Якщо Object o може бути чимось іншим, крім String, вам потрібно буде викликати toString ().


Це правильна відповідь для мене. Чому? Оскільки кастинг (string)Registry.GetValue...видає виняток для спроби закинути об’єкт Int32, тоді як Registry.GetValue...ToString()працює, як очікувалося.
гравітація

3

Я б не був надто стурбований продуктивністю, якщо ця операція робиться навіть лише кілька тисяч разів на секунду - відчутної різниці немає.

Однак мене турбує "знання" вкладених даних. У вас є метод, який приймає, Objectі ви повинні ставитися до нього як до такого, тобто ви не повинні знати нічого про параметр, крім того, що він приєднується до Objectінтерфейсу, який, як трапляється, маєtoString() метод. У цьому випадку я настійно рекомендую використовувати цей метод, а не просто припускати щось.

Ото, якщо вхід завжди або Stringабо nullпросто змінити спосіб прийняти Stringс, і явно перевірити nullс (які ви повинні робити в будь-якому випадку , коли справа з не-примітивів ...)


Я сказав, що моє запитання не має цінного значення :) Мені просто цікаво, що теоретично дешевше. Але все одно спасибі
Вуглускр,

Вартість буде залежати від того, наскільки ефективна віртуальна машина при викликах віртуальних методів проти перевірки типу. Це залежить від реалізації.
Джон Скіт,

2

Враховуючи, що посилальний тип - це Об’єкт, і всі Об’єкти мають toString (), просто викличте object.toString (). String.toString () просто повертає це.

  • toString () - це менше коду для введення.
  • toString () - менше байт-коду.
  • кастинг - дорога операція проти поліморфного виклику.
  • акторський склад міг зазнати невдачі.
  • Використовуйте String.valueOf (object), який просто викликає object.toString (), якщо він не є null.

1

Якщо те, що у вас є в "o", є рядком, тоді різниці не дуже великої (швидше за все, приведення відбувається швидше, але це справа реалізації VM / бібліотеки).

Якщо "o" може не бути String, але це має бути String, тоді привід - це те, що ви хочете (але ви повинні змусити метод взяти String замість Object).

Якщо "o" може бути будь-якого типу, то вам доведеться використовувати toString - але спочатку переконайтеся, що немає null.

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;
    }    
}

або

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();
    }
}

Краще кодувати останню як:

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

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

    str = o.toString();
}

Перші 2 фрагменти насправді не компілюються ( finalзмінна, можливо, не була ініціалізована). Вам потрібна програма, elseяка або викине виняток, або ініціалізує strщось.
Bruno Reis

1

Я дивно виявив, що каст був повільнішим, ніж пошук vtable, передбачений викликом tostring.


1

Не може бути "нульовий рядок у o". Якщо o має значення null, воно не містить нульового рядка, воно просто має значення null. Просто спочатку перевірте o на нуль. Якщо ви кинете або зателефонуєте ToString () на нуль, ви зазнаєте аварії.


2
Нульове відтворення не призведе до аварії. Він навіть не викине NullPointerException, він просто викличе null до нового типу. :)
Бомбе
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.