Почему формат String (Object... args) определяется как статический метод?

Интересно, почему Java 5 и выше предоставляют форматтер в стиле printf, используя статический метод в классе String, например так:

public static String format(String format, Object... args)

вместо

public String format(Object... args)

так что мы можем написать "%02d".format(5) получить 05 вместо String.format("%02d", 5),

Я подумал, что если бы я мог изменить класс String, я мог бы добавить это:

public String format(Object... args) {
    return format(this, args)
}

чтобы получить тот же результат.

Я обнаружил, что в C# статический метод также используется вместо метода экземпляра.

Интересно, почему они решили это сделать, но я не пришел к объяснению. Методы экземпляра trim а также substring возвращает новый экземпляр строки, поэтому они должны были сделать то же самое с format,

Кроме того, DateFormat Класс также использует это:

public final String format(Date date)

для форматирования дат. Поэтому, если мы рассмотрим экземпляр DateFormat в качестве средства форматирования, экземпляр String также можно будет использовать в качестве средства форматирования.

Есть идеи?

14 ответов

Решение

Возможно "%02d".format(5) кажется, подразумевает, что объект, на котором format Метод вызывается в формате строки.

В этом случае строка формата также String Продолжая эту мысль, можно утверждать, что все String s - это строки формата.

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

Хотя я не являюсь разработчиком Java, я могу сказать вам одну очевидную причину, чтобы сделать его статичным.

Java 5 вышла с множеством функций, но две заметки были:

  • Способность выполнять команды "import static", позволяющие легко использовать статические методы внутри класса и без указания имени класса.
  • Статический служебный метод, который легко выполняет printfs.

Хотя было бы неплохо иметь возможность сказать, "bla: %d".format("foo"), сделав метод статичным, вы можете использовать форматирование таким способом, который очень знаком и понятен программистам на C printf(),

import static java.lang.String.format;

public class Demo {

   public void Test() {

      //Do some stuff

      format("Hey, this is easy to read!");

   }
 }

И вот почему! При использовании статического импорта printfs выглядят почти так же, как в C. Awesome!

Основная причина, вероятно, заключается в том, что разработчики Java не хотели добавлять слишком много вещей в интерфейс String. Создание функции-члена означало бы поместить ее в строку. Помните, что нестатический метод должен быть в объекте String.

Вторая причина в том, что статический формат сохраняет сходство с printf C, который выглядит как printf(FORMAT, ARG1, ARG2...)

Другая причина в том, что формат перегружен: есть версия, которая принимает локаль в качестве первого параметра (перед строкой), поэтому сделать это на строковом объекте было бы сложно.

"%02d".format(5) будет выглядеть так, как будто "% 02d" отформатирован с использованием формата 5, а не наоборот. Кроме того, большинство строк не подходят в качестве формата ("hello world".format(5)?), Поэтому метод должен выдавать исключения для большинства строковых объектов.

Ответ лежит на методе Format.

По крайней мере для меня более логично и интуитивно сказать, что "строка формата является входом для метода формата", чем сказать, что "Формат работает с строкой формата". Это так, поскольку мы "обычно" передаем форматную строку, известную во время разработки, в Format. Напротив, для Trim мы "обычно" передаем переменную строку, значение которой неизвестно во время разработки.

Таким образом, делая метод форматирования статическим, сделайте чтение кода более интуитивным. Посмотрите на следующее (C#).

answer = String.Format("This is format string : {0}", someValue); 
//More readable to me

answer = "This is format string : {0}".Format(someValue);

РЕДАКТИРОВАТЬ: Несмотря на то, что я использовал пример кода C#, это хорошо относится к Java. Я получил -ve голос за использование синтаксиса C#!

Я действительно думаю format должен быть методом экземпляра String и поэтому также делать

  • питон:
    2.6: вывести "%s" % ("Привет")
    3.0: печать ("{0}". Формат ("Привет"))
  • Скала:
    2.7.6: println ("% s".format ("Hello"))

Вызов strfmt.format (объекты) вместо String.format(strfmt, объекты)

  • это объектно-ориентированный вызов вместо вызова статического помощника.
  • его короче типу.
  • это проще, так как имеет на один аргумент меньше.
  • его проще использовать с дополнением кода. Если вы начинаете со строки формата и нажимаете. Вы получаете формат () в качестве опции в IDE.
  • String.format(strfmt, objects) может быть случайно назван strfmt.format(text, objects), который не будет делать то, что кажется.

Просто потому, что звонок напоминает о С sprintf функция.

Я думаю, что это не обязательно, что Java делает любую конструкцию похожей на что-либо еще, даже C++. Все, что принято, должно быть так, потому что разработчики принимают это. Кроме того, аргументы типа "они сделали его похожим на что-то другое" не объясняют, почему они не просто делают версию метода экземпляра, они делают это с помощью примитивных оболочек (в дополнение к методу toString() экземпляра у них есть статическая версия).).

Вот что я думаю:

В нормальном случае обе формы эквивалентны, но предположим, что у нас есть что-то вроде:

String invalidFormat = "%invalid"; // or something else that is invalid

и тогда мы называем:

String.format(invalidFormat, anything);
// "anything" is indeed anything....

недопустимый становится аргументом, и Java проясняет это, бросая экземпляр IllegalArgumentException (даже в случае с Formatter, существует много видов).

Тем не менее, в чем-то вроде:

invalidFormat.format(anything);

неверный больше не аргумент. Теперь проблема заключается в экземпляре, к которому он вызывается, и поэтому, вероятно, лучше описать его как "недопустимое состояние" (а не "IllegalStateException" Java, который имеет совершенно другое использование). Но поскольку строки неизменяемы, это так называемое "состояние" никогда не изменится, поэтому оно всегда будет оставаться недопустимым как формат, даже если это допустимая простая строка.

Сравните это, скажем, с java.lang.Long. Обе версии toString никогда не вызовут никаких исключений, поэтому они обе эквивалентны.

answer = String.Format("This is format string : {0}", someValue); 
//More readable to me

answer = "This is format string : {0}".Format(someValue);

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

Просто плохой дизайн. Питонер находит это болезненным.

Возможно, чтобы показать, что это "полезная" функция, которая существует для удобства, но на самом деле не является встроенной функцией String. То есть строка "%02d" это способ представления формата, но он не выполняет никакого форматирования.

Метод существует для удобного форматирования строк, но Formatter (который выполняет фактическое форматирование) также может форматировать другие типы объектов (дата и т. Д.).

В C# строки неизменны. Я думаю, что это верно и для Java (не уверен на 100%). Таким образом, вы не изменяете строку, вызывая для нее метод форматирования, вы только возвращаете новую строку с форматированием. Это делает его методом уровня класса, а не методом уровня экземпляра, поэтому он является статическим. Вы можете добавить фасад уровня экземпляра в C#, используя функцию расширения, но это просто синтаксический сахар поверх статической функции.

Другие вопросы по тегам