(Строка) или .toString ()?

89

У меня есть метод с Object oпараметром.

В этом методе я точно знаю, что Stringв «o» есть ненулевое значение. Проверять или делать что-то еще не нужно. Я должен относиться к нему как к Stringпредмету.

Просто любопытно - что дешевле - закинуть String, или использовать Object.toString()? Или по цене времени / процессора / памяти то же самое?

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

А этого не может быть nullвообще. Я просто хотел сказать, что мне не нужно проверять его на нуль или пустоту. В моем случае всегда есть непустая строка.

Вуглускр
источник
1
В мире .NET мы измерили это, и ToString () работает быстрее. Учитывая причину, по которой это так, то же самое почти наверняка верно и для jiting JVM.
Джошуа

Ответы:

73

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

эйфория83
источник
4
Вы тестировали его на нескольких JRE? Я видел удивительные результаты именно для этой ситуации в .NET. На самом деле я сомневаюсь, что производительность будет иметь значение в реальной жизни, но кастинг лучше с точки зрения защитного кодирования.
Джон Скит,
Вызов метода должен быть встроен. Было бы лучше всего использовать дженерики для удаления (явного) приведения.
Том Хотин - tackline
@Jon Skeet: Я согласен, что разница в производительности будет небольшой. @Tom Hawtin: Поскольку тип объекта, который будет получен, неизвестен во время компиляции, я не вижу, как вызов метода может быть встроен. Можете уточнить плз?
euphoria83
@ euphoria83: встроен JIT-компилятором, а не javac.
Майкл Майерс
На самом деле нет, метод не может быть встроен. Тип известен только как объект, а фактическая реализация зависит от типа среды выполнения. Какой из них быстрее, все еще зависит от реализации, но насколько я помню (я действительно тестировал его с помощью микробенчмарка в какой-то момент), кастинг оказывается быстрее. Это не очевидный ответ: проверка типов не всегда выполняется быстрее. Для типа String это может быть объект (а не интерфейс), причем последний.
StaxMan
45

Я бы использовал гипс. Это подтверждает ваше «знание» того, что это строка. Если по какой-либо причине вы обнаружите ошибку, и кто-то передаст что-то, кроме строки, я думаю, было бы лучше выбросить исключение (что и сделает приведение), чем продолжать выполнение с ошибочными данными.

Джон Скит
источник
7

Если вы знаете, что Object o является String, я бы сказал, просто приведите его к String и обеспечьте его таким образом. Вызов toString () для объекта, который, как вы точно знаете, является String, может только добавить путаницы.

Если Object o может быть чем угодно, кроме String, вам нужно вызвать toString ().

Энди Уайт
источник
Это правильный ответ для меня. Зачем? Потому что приведение (string)Registry.GetValue...вызывает исключение при попытке привести объект Int32, тогда как Registry.GetValue...ToString()работает должным образом.
гравитационный
3

Меня бы не особо волновала производительность, если эта операция выполняется хотя бы несколько тысяч раз в секунду - ощутимой разницы нет.

Однако я был бы обеспокоен "знанием" ввода. У вас есть метод, который принимает, Objectи вы должны рассматривать его как таковой, т.е. вы не должны ничего знать о параметре, кроме того, что он привязан к Objectинтерфейсу, у которого есть toString()метод. В этом случае я настоятельно рекомендую использовать этот метод вместо того, чтобы просто предполагать что-либо.

OTOH, если вход всегда либо Stringили null, просто измените метод, чтобы принять Strings, и явно проверьте nulls (что вы должны делать в любом случае, когда имеете дело с непримитивами ...)

Хенрик Пол
источник
Я сказал, что мой вопрос не имеет смысла :) Просто мне интересно, что теоретически дешевле. Но все равно спасибо
Vugluskr
Стоимость будет зависеть от того, насколько эффективна виртуальная машина при вызовах виртуальных методов по сравнению с проверкой типов. Это зависит от реализации.
Джон Скит,
2

Учитывая, что ссылочный тип - это объект, а все объекты имеют toString (), просто вызовите object.toString (). String.toString () просто возвращает это.

  • toString () - это меньше кода для ввода.
  • toString () меньше байт-кода.
  • кастинг - дорогостоящая операция по сравнению с полиморфным вызовом.
  • бросок мог потерпеть неудачу.
  • Используйте String.valueOf (object), который просто вызывает object.toString (), если он не равен нулю.
mP.
источник
1

Если то, что у вас есть в «o», является String, тогда нет большой разницы (вероятно, приведение быстрее, но это вещь реализации 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что-то инициализирует .
Бруно Рейс
1

Как ни странно, я обнаружил, что приведение выполняется медленнее, чем поиск vtable, подразумеваемый вызовом tostring.

Джошуа
источник
1

В o не может быть «нулевой строки». Если o имеет значение NULL, он не содержит нулевой строки, это просто NULL. Просто сначала отметьте o на null. Если вы бросили или вызов ToString () на нуль рухнет.

Эд С.
источник
2
Приведение к нулю не приведет к сбою. Он даже не вызовет исключение NullPointerException, он просто вызовет null для нового типа. :)
Bombe