Делает ли пустую строку постоянной?

У меня есть сотрудник, который клянется

//in a singleton "Constants" class
public static final String EMPTY_STRING = "";

в классе констант, доступном во всем проекте. Таким образом, мы можем написать что-то вроде

if (Constants.EMPTY_STRING.equals(otherString)) {
    ...
}

вместо

if ("".equals(otherString)) {
    ...
}

Я говорю это

  • не стоит - он не сохраняет пробел в пуле кучи/стека/строки,
  • некрасиво
  • злоупотребление классом констант.

Кто здесь идиот?

Ответ 1

Строковые литералы интернированы по умолчанию, поэтому независимо от того, сколько раз вы ссылаетесь на "" в коде, будет только один пустой объект String. Я не вижу никакой пользы в объявлении EMPTY_STRING. В противном случае вы можете также объявить ONE, TWO, THREE, FOUR и т.д. Для целых литералов.

Конечно, если вы хотите позже изменить значение EMPTY_STRING, удобно иметь его в одном месте;)

Ответ 2

Зачем вам нужна глобальная переменная в Java? Джеймс Гослинг действительно пытался избавиться от них; не возвращайте их, пожалуйста.

Либо

0 == possiblyEmptyString.length()

или

possiblyEmptyString.isEmpty() // Java 6 only

так же понятны.

Ответ 3

Я предпочитаю видеть EMPTY_STRING.

Это делает его английским. ".equals" читает "иначе, чем EMPTY_STRING.equals.

Ответ 4

По иронии судьбы, вся точка констант состоит в том, чтобы сделать их легко изменчивыми. Поэтому, если ваш коллега не планирует переопределять EMPTY_STRING, чтобы быть чем-то иным, чем пустой строкой, - что было бы действительно глупо, - отличная подлинная фиксированная конструкция, такая как "", является плохой.

Как говорит Дэн Дайер, его, как определение константы ONE 1: это совершенно бессмысленно и будет совершенно запутанным - потенциально опасным - если кто-то переопределит его.

Ответ 5

Ну, я тоже мог догадаться, но я сделал быстрый тест... Почти как обман...

Произвольная строка проверяется различными способами. (несколько итераций)

Результаты показывают, что isEmpty() быстрее и действительно читается; Если isEmpty() недоступен, length() является хорошей альтернативой.

Использование константы, вероятно, не стоит.

"".equals(someString())      :24735 ms
t != null && t.equals("")    :23363 ms
t != null && t.equals(EMPTY) :22561 ms
EMPTY.equals(someString())   :22159 ms
t != null && t.length() == 0 :18388 ms
t != null && t.isEmpty()     :18375 ms
someString().length() == 0   :18171 ms

В этом сценарии

"IAmNotHardCoded".equals(someString())

Я бы предложил определить константу в r e l e v a n t place, так как глобальный класс для всех констант действительно отстой. Если нет подходящего места, вы, вероятно, делаете что-то еще неправильно...

Customer.FIELD_SHOE_SIZE //"SHOE_SIZE"

Может считаться подходящим местом, где:

CommonConstants.I__AM__A__LAZY__PROGRAMMER // true

нет.

Для BigIntegers и подобных вещей я, как правило, заканчиваю определение конечного статического локально; как:

private final static BigDecimal ZERO = new BigDecimal(0);
private final static BigDecimal B100 = new BigDecimal("100.00");

Thats bugs me and would be be nice with some sugar for BigInts и BigDecimals...

Ответ 6

Я с твоей коллегой. Хотя пустая строка трудно ошибиться, вы можете случайно разместить там место, и при сканировании кода это может быть трудно заметить. Более того, это хорошая практика сделать это со всеми вашими строковыми константами, которые используются в нескольких местах - хотя я стараюсь делать это на уровне класса, а не как глобальные константы.

FWIW, С# имеет статическую строку свойств. Этот вариант используется только для этой цели, и я обнаружил, что он значительно улучшает читабельность кода.

Ответ 7

Мне не нравится выбор. Почему бы не if (otherString.length() == 0)

Изменить: я на самом деле всегда код

if (otherString == null || otherString.length() == 0)

Ответ 8

Как касательная к вопросу, я обычно рекомендую использовать функцию утилиты, когда то, что вы действительно проверяете, - это "не полезное значение", а не пустая строка. В общем, я склонен использовать:

import org.apache.commons.lang.StringUtils;

// Check if a String is whitespace, empty ("") or null.
StringUtils.isBlank(mystr); 
// Check if a String is empty ("") or null.
StringUtils.isEmpty(mystr); 

Понятие о том, что два выше:

  • Проверьте различные другие случаи, в том числе с нулевой безопасностью и (что более важно)
  • Предоставляет то, что вы пытаетесь протестировать, а не как его протестировать.

Ответ 9

Тот же аргумент появляется в .NET время от времени (там, где уже есть статическая строка только для чтения. Empty). Это вопрос вкуса - но лично я считаю "менее навязчивым".

Ответ 10

В одном случае, когда имеет смысл иметь константу со значением пустой строки, это когда вы захватываете семантику значения. Например:

if (Constants.FORM_FIELD_NOT_SET.equals(form.getField("foobar"))) {
    ...
}

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

Ответ 11

Хехе, забавная вещь: После компиляции вы не увидите разницу (в байтовом коде) между "статической конечной" вещью и строковым литералом, так как Java-компилятор всегда вставляет "статическую конечную строку" в целевой класс. Просто измените пустую строку на нечто узнаваемое (например, текст LGPL) и посмотрите на полученный файл *.class кода, который ссылается на эту константу. Вы найдете текст, скопированный в этот класс файл.

Ответ 12

Дэвид Арно утверждает: -

По иронии судьбы весь смысл константы - сделать их легко изменчива

Это просто неверно. Вся точка констант - это повторное использование того же значения и для большей читаемости.

Очень редко изменяются постоянные значения (отсюда и название). Чаще всего значения конфигурации изменяются, но сохраняются как данные где-то (например, файл конфигурации или запись в реестре)

С раннего программирования константы использовались для превращения таких вещей, как критические шестнадцатеричные значения, такие как 0xff6d8da412, во что-то человеко читаемое без ever, намеревающееся изменить значения.

const int MODE_READ       = 0x000000FF;
const int MODE_EXECUTE    = 0x00FF0000;
const int MODE_WRITE      = 0x0000FF00;
const int MODE_READ_WRITE = 0x0000FFFF;

Ответ 13

Мы просто делаем следующее для таких ситуаций:

public class StaticUtils
{
    public static boolean empty(CharSequence cs)
    {
        return cs == null || cs.length() == 0;
    }

    public static boolean has(CharSequence cs)
    {
        return !empty(cs);
    }
}

Тогда просто import static StaticUtils.*

Ответ 14

  • да - он не дает никакой пользы.
  • зависит от того, к чему вы привыкли. Я уверен.
  • Нет, это просто постоянный - не злоупотребление.

Ответ 15

Хм, правила правильные, но принимаются в другом смысле! Давайте рассмотрим причину, во-первых, все ссылки на объекты в java проверяются равными(). Ранее на некоторых языках это было сделано с использованием оператора "==", если случайно кто-то использовал "=" для "==", катастрофу. Теперь вопрос о магических числах/константах, для компьютера все константы/числа схожи. Вместо "int ONE = 1" можно с уверенностью использовать 1, но это будет верно для двойного PI = 3.141...? Что произойдет, если кто-то позже попытается изменить точность.

Если бы мы придумали контрольный список, то какое правило было бы направлено на общее руководство, не так ли? Все, что я хочу сказать, это то, что правила должны помочь, мы сможем наверстывать правила только тогда, когда мы их очень хорошо знаем. Здравый смысл превалирует. Как предложил мой друг, константы программы, такие как 0/1, которые обозначают условия выхода, могут быть жестко закодированы и, следовательно, принцип магического числа не применяется. Но для тех, кто участвует в логических проверках/правилах, лучше сохраняйте их как настраиваемые константы.

Ответ 16

Почему предпочтительнее использовать String.Empty в С# и, следовательно, общедоступную константу на других языках, состоит в том, что константы являются статическими, поэтому занимают только один экземпляр в памяти.

Каждый раз, когда вы делаете что-то вроде этого: -

stringVariable = "";

вы создаете новый экземпляр нулевой строки и указываете на него с помощью stringVariable.

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

инициализируя строки, указывая их все на одну и ту же константу, означает, что создается только одна "", и каждая инициализированная переменная указывает на ту же нулевую строку.

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

Как обычно, инициализация строки является хорошей практикой: -

const String EMPTY_STRING = "";
String variable1 = EMPTY_STRING;
String variable2 = EMPTY_STRING;
String variable3 = EMPTY_STRING;
String variable4 = EMPTY_STRING;
String variable5 = EMPTY_STRING;

Вы создали 5 указателей строк, но только 1 строка

а не: -

String variable1 = "";
String variable2 = "";
String variable3 = "";
String variable4 = "";
String variable5 = "";

Вы создали 5 указателей строк и 5 отдельных нулевых строк.

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

Конечно, компиляторы должны быть достаточно умны, чтобы определить несколько статических строк и повторное использование дубликатов, но зачем предполагать?

Кроме того, он менее подвержен внедрению ошибок, поскольку "и" " будут компилироваться, но вы можете пропустить место, которое вы случайно добавили, что может вызвать ложные ошибки времени выполнения, например условную логику, такую ​​как: -

myvariable = " ";
While (myVariable == ""){
 ...
}

Код внутри блока while недоступен, потому что myVariable не удовлетворяет условию первой итерации. Ошибка инициализации с помощью "вместо" " легко пропустить, тогда как: -

myvariable = EMPTY_STRING;
While (myVariable == EMPTY_STRING){
 ...
}

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

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

public static class StringConstants{
    public static String Empty = "";
    public static String EMail = "mailto:%s";
    public static String http = "http://%s";
    public static String https = "https://%s";
    public static String LogEntry = "TimeStamp:%tYmdHMSL | LogLevel:%s| Type:%s | Message: '%s'";

}

String myVariable = StringConstants.Empty;

Возможно, вы даже сможете расширить собственный объект String, в зависимости от вашего языка.

Ответ 17

Если вы хотите сохранить "пустые" строки в столбце нулевой строки в оракуле, вам придется изменить определение EMPTY_STRING как нечто иное, чем ""! (Я вспоминаю, что в последний раз я был вынужден использовать Oracle, чтобы он не знал разницы между пустой строкой и пустой строкой).

Однако это должно быть сделано на вашем уровне доступа к данным, поэтому остальная часть приложения не знает об этом и/или сортирует вашу модель данных, поэтому вам не нужно хранить пустую строку И нулевые строки в том же столбце.