Por que não existe String.Empty em Java?

260

Entendo que toda vez que digito a string literal "", o mesmo objeto String é referenciado no pool de strings.

Mas por que a API String não inclui um public static final String Empty = "";, para que eu pudesse usar referências String.Empty?

Isso economizaria tempo de compilação, no mínimo, já que o compilador saberia fazer referência à String existente e não precisaria verificar se ele já havia sido criado para reutilização, certo? E, pessoalmente, acho que uma proliferação de literais de strings, especialmente pequenos, em muitos casos é um "cheiro de código".

Então havia um motivo de design grande por trás do String.Empty, ou os criadores de idiomas simplesmente não compartilharam minhas opiniões?

Tom Tresansky
fonte
5
Aidanc: Eu acho que ele significa situações onde você fazer coisas assim outputBlah = "", e provavelmente ele prefere something == String.Emptymais something.Length > 0bem (você pular um cheque nulo.)
Skurmedel
2
@Aidanc - Ele estava procurando por um "membro vazio" como Collections.EMPTY_SET , não uma função para verificar a seqüência de caracteres "vazio".
Tim Pedra
2
@Aidanc: O que inspirou isso é realmente 'TextBox.setText ("");'.
precisa saber é o seguinte
3
Há uma String.isEmpty()função ... por que você quer String.EMPTY?
Buhake Sindi
8
String.isEmpty()não retorna uma string vazia.
Steve Kuo

Respostas:

191

String.EMPTYtem 12 caracteres e ""dois, e ambos referenciam exatamente a mesma instância na memória em tempo de execução. Não sei ao certo por String.EMPTYque economizaria tempo de compilação, na verdade acho que seria o último.

Especialmente considerando que Strings são imutáveis, não é como se você pudesse primeiro obter uma String vazia e executar algumas operações nela - melhor usar uma StringBuilder(ou StringBufferse você quiser ser seguro para threads) e transformá-la em uma String.

Atualização
Do seu comentário à pergunta:

O que inspirou isso é realmente TextBox.setText("");

Acredito que seria totalmente legítimo fornecer uma constante em sua classe apropriada:

private static final String EMPTY_STRING = "";

E, em seguida, referenciá-lo como no seu código como

TextBox.setText(EMPTY_STRING);

Dessa forma, pelo menos você está explícito que deseja uma String vazia, em vez de se esquecer de preencher a String no seu IDE ou algo semelhante.

Noel M
fonte
14
Ainda vou marcar você com +1, mas me sinto suja porque você mencionou StringBuildersem falar sobre como nove em cada dez vezes é totalmente inapropriado usar em StringBuildervez de concatenação.
Randolpho
85
Costumo preferir string.empty, principalmente porque é mais explícito. Além disso, existem situações em que é mais difícil diferenciar visualmente "" e coisas como "'". No final, como outros observaram, é apenas uma daquelas coisas sem sentido de estilo que nos dão forragem para discutir quando estamos entediados com o trabalho real. =)
JohnFx
@Modelo M: Em relação ao tempo de compilação, eu assumiria que, se houver 2 literais de string definidos em 2 arquivos de origem diferentes com o mesmo valor de string, quando o compilador atingir o 2º, ele precisará fazer algum tipo de verificação para descobrir " ei, eu já conheço essa string daqui ". Eu sou reconhecidamente nenhum especialista no compilador java, mas como isso NÃO poderia ser o caso? E eu acho que pular essa verificação resultaria em uma melhoria minúscula nos tempos de compilação.
precisa saber é o seguinte
@ Tom - Eu acredito que a internação de String é feita em tempo de execução, não em tempo de compilação; portanto, se você tiver a string vazia como uma constante em outro arquivo, o compilador precisará fazer referência a essa classe para resolver o literal String.
Noel M
1
@Randolpho Ao usar a concatenação de strings, você está realmente usando um StringBuilder sob o capô.
Ubuntu #
133

Usar org.apache.commons.lang.StringUtils.EMPTY

jade
fonte
30
Parece muito melhor e mais fácil de ler do que um "" vazio. Espero que não seja só eu.
Lakatos Gyula
2
@LakatosGyula - Eu acho que pode ser (apenas você). Programadores Java proficientes não têm problemas para ler ""... e a maioria provavelmente se oporia em voz alta ao uso, EMPTYexceto em situações EMPTYespecíficas em que o significado é específico do domínio. (E, em tais casos, há provavelmente um nome mais apropriado.)
Stephen C
14
@LakatosGyula Não é só você. Eu fui do desenvolvimento Java para o .NET e o String.Empty foi um recurso que tive o prazer de encontrar na estrutura. Eu gosto da natureza explícita disso em um conjunto vazio de aspas.
yohohoho 27/02
64
@StephenC Quando vejo um "" vazio, a primeira coisa que me ocorre é que é um bug, alguém não terminou a função etc. Com String.EMPTY eu sei exatamente que o desenvolvedor pretendia retornar um string vazio.
Lakatos Gyula 03/03
1
Também é útil para todos os momentos em que o linter diz "use uma constante nomeada em vez de blá blá blá". Todo programador sabe que "" não é mágico, mas não é melhor explicar ao cliente.
LizH
28

Se você deseja comparar com uma sequência vazia sem se preocupar com valores nulos, faça o seguinte.

if ("".equals(text))

Por fim, você deve fazer o que acredita ser mais claro. A maioria dos programadores assume que "" significa string vazia, não uma string em que alguém esqueceu de colocar algo.

Se você acha que há uma vantagem de desempenho, deve testá-la. Se você não acha que vale a pena testar por si mesmo, é uma boa indicação de que realmente não vale a pena.

Parece que você tenta resolver um problema que foi resolvido quando o idioma foi projetado há mais de 15 anos.

Peter Lawrey
fonte
1
Estou muito atrasado para a festa, mas, como as seqüências Java são imutáveis, acredito que todas as sequências vazias em uma JVM são apenas referências diferentes para o mesmo objeto String. Então simplesmente o seguinte também está correto: if ("" == text)
Ajoy Bhatia
12
@AjoyBhatia O problema é que você pode criar novas strings vazias. if ("" == new String())é falso. Um teste melhorif(text.isEmpty())
Peter Lawrey
1
@AjoyBhatia - Somente se as strings estiverem internadas. stackoverflow.com/questions/10578984/what-is-string-interning
Davor
9

Se você realmente deseja uma constante String.EMPTY, pode criar uma classe final estática de utilitário chamada "Constants" (por exemplo) em seu projeto. Esta classe manterá suas constantes, incluindo a String vazia ...

Na mesma idéia, você pode criar constantes ZERO, ONE int ... que não existem na classe Integer, mas como eu comentei, seria uma pena escrever e ler:

for(int i=Constants.ZERO; ...) {
    if(myArray.length > Constants.ONE) {
        System.out.println("More than one element");
    }
}

Etc.

Benoit Courtine
fonte
8

O Apache StringUtils também resolve esse problema.

Falhas nas outras opções:

  • isEmpty () - não é nulo seguro. Se a sequência for nula, lança um NPE
  • length () == 0 - novamente não é nulo seguro. Também não leva em consideração cadeias de espaços em branco.
  • Comparação com a constante VAZIA - Pode não ser nulo seguro. Problema em espaço em branco

O StringUtils concedido é outra biblioteca para arrastar, mas funciona muito bem e economiza muito tempo e verificação de problemas para obter valores nulos ou manipular NPEs normalmente.

Freiheit
fonte
3
então ... parece que a única opção segura é a terrível condição Yoda "".equals(s):?
Lie Ryan
8

Não basta dizer "o pool de memória de strings é reutilizado na forma literal, caso encerrado". O que os compiladores fazem sob o capô não é o ponto aqui. A pergunta é razoável, especialmente considerando o número de votos recebidos.

É sobre a simetria , sem ela as APIs são mais difíceis de usar para seres humanos. Os primeiros SDKs do Java ignoraram notoriamente a regra e agora é meio tarde demais. Aqui estão alguns exemplos em cima da minha cabeça, fique à vontade para usar seu exemplo "favorito":

  • BigDecimal.ZERO, mas não AbstractCollection.EMPTY, String.EMPTY
  • Array.length mas List.size ()
  • List.add (), Set.add (), mas Map.put (), ByteBuffer.put () e não vamos esquecer StringBuilder.append (), Stack.push ()
Slawomir
fonte
Mesmo se você tiver nomeado o parâmetro List length (), ainda precisará dos parênteses, pois é um método. Array.length é uma variável final pública, que funciona apenas porque Arrays são imutáveis. Então você ainda teria Array.length e List.length (). Eu argumentaria que é mais confuso e propenso a erros. Quanto a .append () e .push (), enquanto eles executam tarefas semelhantes, acho que foram nomeados apropriadamente. Anexar a String é exatamente o que você está fazendo, mas você não "anexa" uma Pilha, pressiona e abre valores. E StringBuilder.push () implicaria StringBuilder.pop (), o que não é possível.
Craig Parton
Vindo de modelos / genéricos, interfaces consistentes também ajudam com algoritmos. Se um algoritmo precisa do tamanho de uma coleção, length (T) ou T.length () é tudo o que importa. Da mesma forma, adicionar ao final de uma pilha, lista ou string pode ser feito por um universal add () ou append (). Você mencionou que a matriz em Java é do tipo imutável / embutida com uma propriedade de comprimento exposto. Tudo bem, isso não significa que o compilador não possa manipular ou gerar código para length (T) ou T.length (). Kotlin gera vários métodos intrínsecos para vários casos.
Slawomir
Mas um método length () nomeado consistentemente apenas permite verificar o comprimento. Quão útil é isso? Se seu objetivo é abstrair Listas e Matrizes para torná-las utilizáveis ​​de alguma forma por meio de uma interface, você também precisará de uma maneira consistente de ler ou gravar dados. Então agora você precisa gerar os métodos get (), set () e add (). Essencialmente, você está criando uma exibição de lista menos funcional da matriz. Como Arrays.asList () está disponível, é fácil de usar e é leve, por que reinventar a roda? Matrizes, listas, StringBuilders e pilhas todos têm uma finalidade específica. Parece melhor projetar sua interface para usar o melhor ajuste.
Craig Parton
5

Todos esses ""literais são o mesmo objeto. Por que fazer toda essa complexidade extra? É apenas mais longo para digitar e menos claro (o custo para o compilador é mínimo). Como as seqüências de caracteres de Java são objetos imutáveis, nunca há necessidade de distinguir entre elas, exceto possivelmente como uma questão de eficiência, mas com a literal de seqüência de caracteres vazia, isso não é grande coisa.

Se você realmente quer uma EmptyStringconstante, faça você mesmo. Mas tudo o que fará é incentivar um código ainda mais detalhado; haverá nunca mais ser qualquer benefício para fazê-lo.

Donal Fellows
fonte
27
x = String.Emptytransmite intenção melhor que x = "". Este último pode ser uma omissão acidental. Dizer que nunca há nenhum benefício está incorreto.
precisa
@ Jeffrey: Eu não acho que concordo particularmente. É uma dessas coisas em que não há regra rígida e rápida, suponho.
Donal Fellows
Sim, é importante ressaltar que o compilador java verifica se os literais de string já existem antes de criar uma nova instância no pool de strings.
Rds #
1
@ Jeffrey - sabendo que esta é uma discussão muito antiga e subjetiva. x = String.Emptytransmite intenção, é verdade. Mas suponha que a linguagem forneça uma constante String.Empty, quando você encontrar, x = ""ainda saberá exatamente sobre a intenção como se não houvesse essa constante. Você precisaria garantir que todos os lugares no código Java do mundo em que uma string vazia fosse pretendida não usassem ""para obter o ganho de informação mencionado. Ironicamente, o C # usa uma constante e incentiva o seu uso, então, como eu disse, sei que é uma discussão muito opinativa.
chiccodoro
@chiccodoro - Sim, é verdade. É por isso que a literal de cadeia vazia ""deve ser ilegal, para descartar acidentes. Estou brincando!
Jeffrey L Whitledge
4

Para adicionar o que Noel M afirmou, você pode examinar esta pergunta e esta resposta mostra que a constante é reutilizada.

http://forums.java.net/jive/message.jspa?messageID=17122

A constante de cadeia é sempre "internada", portanto não há realmente uma necessidade dessa constante.

String s=""; String t=""; boolean b=s==t; // true
James Black
fonte
1
o link está morto.
Diet #
3

Entendo que toda vez que digito o literal String "", o mesmo objeto String é referenciado no pool String.
Não existe essa garantia. E você não pode contar com isso em seu aplicativo, é completamente uma decisão da jvm.

ou os criadores do idioma simplesmente não compartilharam minhas opiniões?
Sim. Para mim, parece coisa de prioridade muito baixa.

Nikita Rybak
fonte
6
Não existe essa garantia ... Bem, o JLS afirma que esse deveria ser o caso.
Tim Pedra
@ Tim Não, a menos que você faça uma chamada 'interna'. É fácil construir duas seqüências grandes iguais programaticamente e verificar.
Nikita Rybak
@ Tim Por exemplo, repita a + = "a"; 100 vezes, faça o mesmo com be verifique.
Nikita Rybak
5
Você está certo, mas o que você descreveu não é uma string literal, nem uma expressão cujo resultado pode ser garantido no momento da compilação (como String username = "Bob" + " " + "Smith";). As seqüências criadas programaticamente não têm garantias de serem internadas, a menos que você chame explicitamente intern()como afirmou. O cenário do OP descreve o uso da literal ""em branco da cadeia de caracteres em todo o código, que é um caso em que a internação automática ocorreria.
Tim Stone
@ Tim String a = ""; for(int i = 0; i < 100; i++) {a += "a";} String b = ""; for(int i = 0; i < 100; i++) {b += "b";} a.intern(); b.intern();Agora o ae bapontam para o mesmo local de memória em PermGen. Veja este artigo
1ac0
1

Resposta tardia, mas acho que acrescenta algo novo a esse tópico.

Nenhuma das respostas anteriores respondeu à pergunta original. Alguns tentaram justificar a falta de uma constante, enquanto outros mostraram maneiras pelas quais podemos lidar com a falta da constante. Mas ninguém forneceu uma justificativa convincente para o benefício da constante; portanto, sua falta ainda não é explicada adequadamente.

Uma constante seria útil porque impediria que certos erros de código passassem despercebidos.

Digamos que você tenha uma grande base de código com centenas de referências a "". Alguém modifica um deles enquanto percorre o código e o altera para "". Essa mudança teria uma grande chance de passar despercebida para a produção; nesse momento, poderá causar algum problema cuja fonte será difícil de detectar.

OTOH, uma constante de biblioteca denominada EMPTY, se sujeita ao mesmo erro, geraria um erro de compilador para algo como EM PTY.

Definir sua própria constante ainda é melhor. Alguém ainda pode alterar sua inicialização por engano, mas devido ao seu amplo uso, o impacto de um erro desse tipo seria muito mais difícil de passar despercebido do que um erro em um único caso de uso.

Esse é um dos benefícios gerais que você obtém ao usar constantes em vez de valores literais. As pessoas geralmente reconhecem que usar uma constante para um valor usado em dezenas de lugares permite que você atualize facilmente esse valor em apenas um lugar. O que é menos frequentemente reconhecido é que isso também impede que esse valor seja acidentalmente modificado, porque essa alteração seria exibida em todos os lugares. Portanto, sim, "" é menor que VAZIO, mas VAZIO é mais seguro de usar que "".

Portanto, voltando à pergunta original, podemos apenas especular que os projetistas de linguagem provavelmente não estavam cientes desse benefício de fornecer constantes para valores literais que são freqüentemente usados. Felizmente, um dia veremos constantes de string adicionadas em Java.

Laurentiu Cristofor
fonte
-16

Para aqueles que reivindicam ""e String.Emptysão intercambiáveis ​​ou ""melhor, você está muito errado.

Cada vez que você faz algo como myVariable = ""; você está criando uma instância de um objeto. Se o objeto String do Java tivesse uma constante pública VAZIA, haveria apenas 1 instância do objeto ""

Por exemplo: -

String.EMPTY = ""; //Simply demonstrating. I realize this is invalid syntax

myVar0 = String.EMPTY;
myVar1 = String.EMPTY;
myVar2 = String.EMPTY;
myVar3 = String.EMPTY;
myVar4 = String.EMPTY;
myVar5 = String.EMPTY;
myVar6 = String.EMPTY;
myVar7 = String.EMPTY;
myVar8 = String.EMPTY;
myVar9 = String.EMPTY;

10 (11 incluindo String.EMPTY) ponteiros para 1 objeto

Ou: -

myVar0 = "";
myVar1 = "";
myVar2 = "";
myVar3 = "";
myVar4 = "";
myVar5 = "";
myVar6 = "";
myVar7 = "";
myVar8 = "";
myVar9 = "";

10 ponteiros para 10 objetos

Isso é ineficiente e, em um aplicativo grande, pode ser significativo.

Talvez o compilador Java ou o tempo de execução seja eficiente o suficiente para apontar automaticamente todas as "" instâncias para a mesma instância, mas pode não ser necessário e requer processamento adicional para fazer essa determinação.

Antony Booth
fonte
9
Errado, de acordo com stackoverflow.com/questions/1881922/… , a sequência "" será reutilizada do pool de Sequências.
RealHowTo 2/12/12
1
Afirmei que ele pode reutilizar o mesmo objeto e, se for o caso, ainda é menos eficiente, porque ele precisa encontrar esse objeto (no pool de cadeias), então como estou errado? Independentemente disso, há várias razões pelas quais String.Empty é superior, incluindo a prevenção de erros como myVar = ""; e legibilidade, bem como a melhoria de desempenho que já afirmei. É uma boa prática usar constantes em vez de criar literais de string, se não por outro motivo; é mais fácil manter o código.
Antony Booth
1
Duvido que seu argumento de desempenho seja válido porque o JLS diz que uma constante será tratada como literal no tempo de compilação ( docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10. 5 ) A legibilidade é um argumento melhor.
RealHowTo 6/03/2012
3
@AntonySmith - Eu acho que você precisa estudar Java um pouco mais ou talvez você já conheça o seu erro. As strings Java são imutáveis ​​e em um pool. Portanto, existe apenas um objeto String para "" em uma JVM, não importa quantas vezes ele seja encontrado no código. Você pode verificar se uma string está vazio, fazendoif (text == "")
Ajoy Bhatia
2
Errado. Este comentário deve ser excluído.
Elad Tabak #