Главная » Java, Советы » Всегда переопределяйте метод toStrlng

0

 

в классе java.lang.Object предусмотрена реализация метода toString, однако возвращаемая им строка, как правило, совсем не та, которую желает видеть пользователь вашего класса. Она состоит из названия класса, за которым следуют символ "коммерческого at" (@) и его хэш-код в виде беззнакового шестнадцатеричного числа, например "PhoneNumbeг@16ЗЬ91". Общее соглашение для метода toString: возвращаемая строка должна быть "лаконичным, но информативным, легко читаемым

 

 

представлением объекта". Хотя можно поспорить, является ли лаконичной и легко читаемой строка "РhопеNumЬег@16ЗЬ91", она не столь информативна, как, например, такая ,строка: "( 408) 867 -5З09’~. Далее в соглашении для метода toSt ring говорится:

"Рекомендуется во всех подклассах переопределять этот метод". Хороший совет, ничего не скажешь.

Эти соглашения не столь строги, как соглашения для методов equals и hashCode (статьи 7 и 8), однако, качественно реализовав метод toString, вы сделаете свой класс более приятным в использовании. Метод toSt ring вызывается автоматически, когда ваш объект передается методу println, оператору сцепления строк (+) или assert (в версии 1.4). Если вы создали хороший метод toString, получить удобное диагностическое сообщение можно простым способом:

 

System.out.println("Failed to connect: "+ phoneNumber);

 

Программисты все равно будут строить такие диагностические сообщения, переопределите вы метод toString или нет, но сообщения не станут понятней, если не сделать этого. Преимущества от реализации удачного метода toString передаются не только экземплярам этого класса, но и объектам, которые содержат ссылки на эти экземпляры, особенно это касается коллекций. Что бы вы хотели увидеть: "{Jеппу=РhопеNumЬег@16ЗЬ91}" или же "{Jenny=(408) 867-5З09}"?

Будучи переопределен, метод toString должен передавать всю полезную информацию, которая содержится в объекте, как это было показано в примере с телефонными номерами. Однако это не годится для больших объектов или объектов, состояние которых трудно представить в виде строки. В подобных случаях метод toString возвращает такое резюме, как "Manhattan white pages (1487536 listings)" или "Thread [main, 5, main]". В идеале полученная строка не должна требовать разъяснений. (Последний пример с Th read не отвечает этому требованию.)

При реализации метода toString вы должны принять одно важное решение: будете ли вы описывать в документации формат возвращаемого значения. Это желательно делать для классов-значении (value class), таких как телефонные номера и таблицы. Задав определенный формат, вы получите то преимущество, что он будет стандартным, однозначным и удобным для чтения представлением соответствующего объекта. Это представление можно использовать для ввода, вывода, а также для создания удобных для прочтения записей в фиксируемых объектах, например в документах XML. При задании определенного формата, как правило, полезно бывает создать соответствующий конструктор объектов типа String (или статический метод генерации, см. статью 1), что позволит программистам с легкостью осуществлять преобразование между объектом и его строковым представлением. Такой подход используется в ‘библиотеках платформы Java для многих классов-значений, включая Biglnteger, BigDecimal и большинство примитивных классов-оболочек (wrapper).

Неудобство от конкретизации формата значения, возвращаемого методом toString, заключается в том, что если ваш класс используется широко, то, задав формат, вы оказываетесь привязаны к нему навсегда. Другие программисты будут писать код, который анализирует данное представление, генерирует и использует его при записи

объектов в базу данных (persistent data). Если в будущих версиях вы поменяете формат представления, они будут очень недовольны, поскольку вы разрушите созданные ими код и данные. Отказавшись от спецификации формата, вы сохраняете возможность внесения в него новой информации н его совершенствования в последующих

версиях.

Будете вы объявлять формат или нет, вы должны четко обозначить ваши

намерения. Если вы описываете формат, то обязаны сделать это пунктуально. В качестве примера представим метод toString, который должен сопровождать класс PhoneNumber (статья 8):

 

/**

* Возвращает представление данного телефонного номера в виде строки.

* Строка состоит из четырнадцати символов, имеющих формат

* "(ХХХ) YYY-ZZZZ" , где ХХХ – код зоны, УУУ – номер АТС,

* ZZZZ – номер абонента в АТС. (Каждая прописная буква представляет * одну десятичную цифру.)

*

* Если какая-либо из трех частей телефонного номера мала и

* не заполняет свое поле, последнее дополняется ведущими нулями. * Например, если значение номера абонента в АТС равно 12З, то

* последними четырьмя символами в строковом представлении будут "0123".

*

* Заметим, что закрывающую скобку, следующую за кодом зоны, и первую * цифру номера АТС разделяет один пробел.

*/

public Stгiпg tоStгiпg() {

геtuгп "(" + tоРаddеdStгiпg(агеаСоdе, З) + ") " +

 tоРаddеdStгiпg(ехсhапgе, 3) + "-" +

toPaddedString(extension, 4);

/**

* Преобразует значение типа iпt в строку указанной длины, дополненную

* ведущими нулями. Предполагается. что i >= О,

* 1 <= 1епgth <= 10, а Integer.toString(i) <= 1ength.

*/

private static String toPaddedString(int i, int  length)

String s = Integer.toString(i);

return ZEROS[length – s.length()] + s;

}

private static String[] ZEROS =

{ “”, "0", "00", "000", "0000",

"00000". "000000", "0000000". "00000000", "ООООООООО"};

 

42Если вы решили не конкретизировать формат, соответствующий комментарий к документации должен выглядеть примерно так:

/**

* Возвращает краткое описание зелья. Точные детали представления

* не конкретизированы и могут меняться, однако следующее представление . * может рассматриваться в качестве типичного:

*

* "[Зелье #9: тип=любовный, аромат=скипидар, вид=тушь]"

*/

public Striпg toString () { … }

 

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

Вне зависимости от того, описываете вы формат или нет, всегда полезно предоставлять альтернативный программный доступ ко всей информации, которая содержится в значении, возвращаемом методом toString. Например, класс PhoneNumber должен включать в себя методы доступа к коду зоны, номеру А те и номеру абонента в А те. В противном случае программистам, которым нужна эта информация, придется делать разбор данной строки. Помимо того, что вы снижаете производительность приложения и заставляете программистов выполнять ненужную работу, это чревато ошибками и приводит к созданию ненадежной системы, которая перестает работать, как только вы меняете формат. Не предоставив альтернативных методов доступа, вы де-факто превращаете формат строки в элемент API, даже если в документации и указали, что он может быть изменен.

 

Источник: Джошуа Блох, Java TM Эффективное программирование, Издательство «Лори»

По теме:

  • Комментарии