JavaRush /Blogue Java /Random-PT /Strings em Java (classe java.lang.String)
Viacheslav
Nível 3

Strings em Java (classe java.lang.String)

Publicado no grupo Random-PT

Introdução

O caminho de um programador é um processo complexo e longo. E na maioria dos casos começa com um programa que exibe Hello World na tela. Java não é exceção (veja Lição: A aplicação "Hello World!" ). Como podemos ver, a mensagem é emitida usando System.out.println("Hello World!"); Se você observar a API Java, o método System.out.println usa String como parâmetro de entrada . Este tipo de dados será discutido.

String como uma sequência de caracteres

Na verdade, String traduzida do inglês é uma string. Isso mesmo, o tipo String representa uma string de texto. O que é uma sequência de texto? Uma string de texto é algum tipo de sequência ordenada de caracteres que se sucedem. O símbolo é char. Sequência – sequência. Então sim, absolutamente correto, String é uma implementação de java.lang.CharSequence. E se você olhar dentro da própria classe String, verá que dentro dela não há nada além de um array de caracteres: private final char value[]; Ela tem java.lang.CharSequenceum contrato bastante simples:
Strings em Java (classe java.lang.String) - 1
Temos um método para obter o número de elementos, obter um elemento específico e obter um conjunto de elementos + o próprio método toString, que retornará isso) É mais interessante entender os métodos que chegaram até nós no Java 8, e isso é : chars()e codePoints() lembre-se do tutorial do Oracle “ Primitive Data” Types "que char é single 16-bit Unicode character. Ou seja, essencialmente char é apenas um tipo com metade do tamanho de um int (32 bits) que representa números de 0 a 65535 (ver valores decimais na tabela ASCII ). Ou seja, se desejarmos, podemos representar char como int. E o Java 8 tirou vantagem disso. A partir da versão 8 do Java, temos IntStream - um fluxo para trabalhar com inteiros primitivos. Portanto, em charSequence é possível obter um IntStream representando chars ou codePoints. Antes de passarmos a eles, veremos um exemplo para mostrar a conveniência dessa abordagem. Vamos usar o compilador Java online Tutorialspoint e executar o código:
public static void main(String []args){
        String line = "aaabccdddc";
        System.out.println( line.chars().distinct().count() );
}
Agora você pode obter vários símbolos exclusivos desta forma simples.

Pontos de código

Então, vimos sobre chars. Agora não está claro que tipo de pontos de código são esses. O conceito de codePoint surgiu porque quando o Java apareceu, 16 bits (meio int) eram suficientes para codificar um caractere. Portanto, char em java é representado no formato UTF-16 (especificação "Unicode 88"). Mais tarde, apareceu o Unicode 2.0, cujo conceito era representar um caractere como um par substituto (2 caracteres). Isso nos permitiu expandir o intervalo de valores possíveis para um valor int. Para obter mais detalhes, consulte stackoverflow: " Comparando um char com um ponto de código? " UTF-16 também é mencionado no JavaDoc para Character . Lá, no JavaDoc, diz que: É In this representation, supplementary characters are represented as a pair of char values, the first from the high-surrogates range, (\uD800-\uDBFF), the second from the low-surrogates range (\uDC00-\uDFFF). bastante difícil (e talvez até impossível) reproduzir isso em alfabetos padrão. Mas os símbolos não terminam com letras e números. No Japão, eles criaram algo tão difícil de codificar como o emoji – a linguagem dos ideogramas e emoticons. Há um artigo interessante sobre isso na Wikipedia: “ Emoji ”. Vamos encontrar um exemplo de emoji, por exemplo este: “ Emoji Ghost ”. Como podemos ver, o mesmo codePoint está indicado ali (valor = U+1F47B). É indicado em formato hexadecimal. Se convertermos para um número decimal, obteremos 128123. Isso é mais do que 16 bits permitidos (ou seja, mais de 65535). Vamos copiá-lo:
Strings em Java (classe java.lang.String) - 2
Infelizmente, a plataforma JavaRush não suporta tais caracteres no texto. Portanto, no exemplo abaixo você precisará inserir um valor em String. Portanto, agora entenderemos um teste simples:
public static void main(String []args){
	    String emojiString = "Вставте сюда эмоджи через ctrl+v";
	    //На один emojiString приходится 2 чара (т.к. не влезает в 16 бит)
	    System.out.println(emojiString.codePoints().count()); //1
	    System.out.println(emojiString.chars().count()); //2
}
Como você pode ver, neste caso 1 codePoint vale para 2 caracteres. Esta é a magia.

Personagem

Como vimos acima, Strings em Java consistem em char. Um tipo primitivo permite armazenar um valor, mas um wrapper java.lang.Charactersobre um tipo primitivo permite fazer muitas coisas úteis com este símbolo. Por exemplo, podemos converter uma string em maiúscula:
public static void main(String[] args) {
    String line = "организация объединённых наций";
    char[] chars = line.toCharArray();
    for (int i = 0; i < chars.length; i++) {
        if (i == 0 || chars[i - 1] == ' ') {
            chars[i] = Character.toUpperCase(chars[i]);
        }
    }
    System.out.println(new String(chars));
}
Bem, várias coisas interessantes: isAlphabetic(), isLetter(), isSpaceChar(), isDigit(), isUpperCase(), isMirrored()(por exemplo, colchetes. '(' tem uma imagem espelhada ')').

Conjunto de cordas

Strings em Java são imutáveis, ou seja, constantes. Isso também é indicado no JavaDoc da própria classe java.lang.String . Em segundo lugar, e também muito importante, as strings podem ser especificadas como literais:
String literalString = "Hello, World!";
String literalString = "Hello, World!";
Ou seja, qualquer string entre aspas, conforme dito acima, é na verdade um objeto. E isso levanta a questão: se usamos strings com tanta frequência e muitas vezes elas podem ser iguais (por exemplo, o texto “Erro” ou “Sucesso”), existe alguma maneira de garantir que as strings não sejam criadas todas as vezes? Aliás, ainda temos o Maps, onde a chave pode ser uma string. Então definitivamente não podemos ter as mesmas strings como objetos diferentes, caso contrário não seremos capazes de obter o objeto do Mapa. Os desenvolvedores Java pensaram, pensaram e criaram o String Pool. Este é um local onde as strings são armazenadas, você pode chamá-lo de cache de strings. Nem todas as linhas terminam aí, mas apenas as linhas especificadas no código por um literal. Você mesmo pode adicionar uma linha ao pool, mas falaremos mais sobre isso mais tarde. Então, na memória temos esse cache em algum lugar. Uma pergunta justa: onde está localizada esta piscina? A resposta para isso pode ser encontrada no stackoverflow: “ Onde fica o pool de constantes String do Java, o heap ou a pilha? " Ele está localizado na memória Heap, em uma área especial de pool de constantes de tempo de execução. O pool de constantes de tempo de execução é alocado quando uma classe ou interface é criada pela máquina virtual a partir da área de métodos - uma área especial no Heap à qual todos os threads dentro da Java Virtual Machine têm acesso. O que o String pool nos oferece? Isto tem várias vantagens:
  • Objetos do mesmo tipo não serão criados
  • A comparação por referência é mais rápida do que a comparação caractere por caractere via iguais
Mas e se quisermos colocar o objeto criado neste cache? Então, temos um método especial: String.intern Este método adiciona uma string ao String Pool. É importante notar que este não é apenas algum tipo de cache na forma de um array (como para números inteiros). O método interno é especificado como "nativo". Isso significa que o método em si é implementado em outra linguagem (principalmente C++). No caso de métodos Java básicos, várias outras otimizações podem ser aplicadas a eles no nível da JVM. Em geral, a magia acontecerá aqui. É interessante ler o seguinte post sobre estagiário: https://habr.com/post/79913/#comment_2345814 E parece uma boa ideia. Mas como isso nos afetará? Mas realmente terá um impacto)
public static void main(String[] args) {
    String test = "literal";
    String test2 = new String("literal");
    System.out.println(test == test2);
}
Como você pode ver, as linhas são iguais, mas o resultado será falso. E tudo porque == compara não por valor, mas por referência. E é assim que funciona:
public static void main(String[] args) {
    String test = "literal";
    String test2 = new String("literal").intern();
    System.out.println(test == test2);
}
Observe que ainda faremos uma nova String. Ou seja, inn nos retornará uma String do cache, mas a String original que procuramos no cache será descartada para limpeza, pois ninguém mais sabe sobre ele. Este é claramente um consumo desnecessário de recursos =( Portanto, você deve sempre comparar strings usando iguais para evitar erros repentinos e difíceis de detectar, tanto quanto possível.
public static void main(String[] args) {
    String test = "literal";
    String test2 = new String("literal").intern();
    System.out.println(test.equals(test2));
}
Equals realiza uma comparação de string caractere por caractere.

Concatenação

Como lembramos, linhas podem ser adicionadas. E como lembramos, nossas strings são imutáveis. Então, como isso funciona? Isso mesmo, é criada uma nova linha, que consiste em símbolos dos objetos que estão sendo adicionados. Existem um milhão de versões de como funciona a concatenação plus. Algumas pessoas pensam que sempre haverá um objeto novo, outras pensam que haverá outra coisa. Mas apenas uma pessoa pode estar certa. E esse alguém é o compilador javac. Vamos usar o serviço de compilador online e executar:
public class HelloWorld {

    public static void main(String[] args) {
        String helloMessage = "Hello, ";
        String target = "World";
        System.out.println(helloMessage + target);
    }

}
Agora vamos salvar como um arquivo zip, extrair para um diretório e executar: javap –c HelloWorld E aqui descobrimos tudo:
Strings em Java (classe java.lang.String) - 3
Em loop, claro, é melhor você mesmo fazer a concatenação via StringBuilder. E não por causa de algum tipo de mágica, mas para que o StringBuilder seja criado antes do ciclo, e no próprio ciclo ocorra apenas acréscimo. Aliás, há outra coisa interessante aqui. Há um excelente artigo: “ String Processing in Java. Parte I: String, StringBuffer, StringBuilder ." Muitas informações úteis nos comentários. Por exemplo, é especificado que ao concatenar uma visualização, new StringBuilder().append()...toString()a otimização intrínseca está em vigor, regulada pela opção -XX:+OptimizeStringConcat, que está habilitada por padrão. intrínseco - traduzido como “interno”. A JVM lida com essas coisas de maneira especial, processando-as como Nativas, mas sem os custos adicionais da JNI. Leia mais: " Métodos Intrínsecos em HotSpot VM ".

StringBuilder e StringBuffer

Como vimos acima, StringBuilder é uma ferramenta muito útil. Strings são imutáveis, ou seja, imutável. E eu quero dobrá-lo. Portanto, temos 2 classes para nos ajudar: StringBuilder e StringBuffer. A principal diferença entre os dois é que o StringBuffer foi introduzido no JDK1.0, enquanto o StringBuilder veio no Java 1.5 como uma versão não sincronizada do StringBuffer para eliminar o aumento da sobrecarga da sincronização desnecessária de métodos. Ambas as classes são implementações da classe abstrata AbstractStringBuilder - uma sequência mutável de caracteres. Uma matriz de charms é armazenada dentro, que é expandida de acordo com a regra: value.length * 2 + 2. Por padrão, o tamanho (capacidade) do StringBuilder é 16.

Comparável

As strings são comparáveis, ou seja, implementar o método compareTo. Isso é feito usando comparação caractere por caractere. Curiosamente, o comprimento mínimo é selecionado entre duas strings e um loop é executado sobre ele. Portanto, compareTo retornará a diferença entre os valores int dos primeiros caracteres não correspondentes até o menor comprimento da string ou retornará a diferença entre os comprimentos das strings se todos os caracteres corresponderem ao comprimento mínimo da string. Essa comparação é chamada de “lexicográfica”.

Trabalhando com strings Java

String tem muitos métodos úteis:
Strings em Java (classe java.lang.String) - 4
Existem muitas tarefas para trabalhar com strings. Por exemplo, em Coding Bat . Há também um curso no coursera: " Algoritmos em Strings ".

Conclusão

Mesmo uma breve visão geral desta classe ocupa uma quantidade impressionante de espaço. E isso não é tudo. Eu recomendo fortemente assistir o relatório do JPoint 2015: Alexey Shipilev - Catechism java.lang.String
#Viacheslav
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION