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


89

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

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

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

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

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


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

Ответы:


73

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


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 (), если он не равен нулю.

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.