Qual é o benefício de ativar as Strings no Java 7?


19

Quando eu estava começando a programar em Java, o fato de que as instruções do switch não usavam strings me frustrou. Então, ao usar o Enums, percebi os benefícios que você obtém com eles, em vez de transmitir valores brutos - segurança do tipo (que facilita a refatoração) e clareza para outros desenvolvedores.

Estou lutando para pensar em uma situação em que, com o SE7, agora decidirei usar um switch com strings como entradas, em vez de Enums. Se eles são implementados através da alternância de cadeias inteiras (por exemplo, em vez de correspondências parciais ou regex), não parece oferecer menos motivos para a alteração do código.

E com as ferramentas IDE e a taxa de leitura / gravação da codificação, eu ficaria muito mais feliz ao gerar um Enum extra do que passar valores de string.

Que benefício eles trazem para nós como programadores? Menos caldeira?

Não parece que o idioma estava clamando por esse recurso. Embora talvez haja um caso de uso que estou ignorando.


As strings já são muito usadas nas instruções de switch, mas como as pessoas não podem usá-las diretamente, elas recorrem a soluções alternativas, como árvores gigantes ou conversões em enums. Ambas as soluções alternativas tornam o código menos legível. Ambas as formas são soluções alternativas e por que usar uma solução alternativa se uma solução implementada nativamente mostrar melhor as intenções dos programadores.
precisa

@PieterB Indiscutivelmente, um Enum está adicionando valor semântico ao invés de ser uma solução alternativa, o que traz segurança de tipo (por exemplo, um erro de digitação será detectado no momento da compilação em vez de levar a um bug). Ele também nos permite refazer todas as instâncias da corda, como utilizado nesse contexto , sem afetar outros usos do que string (o que pode acontecer muitas vezes com objetos de domínio.)
anotherdave

Respostas:


12

Tanto quanto posso dizer, a questão é por que o agrupamento de constantes String em enum não foi considerado suficiente para atender às necessidades dos usuários de idiomas. Isso foi abordado na proposta de recurso oficial anunciada na lista de discussão JDK 7 (project Coin).

De acordo com minha leitura da proposta, a alternativa de usar enumerações foi descartada pelo fato de introduzir tipos de inchaço. Para sua conveniência, parte relevante da proposta é citada abaixo, com a declaração endereçando enumerações em negrito :

MAIOR VANTAGEM: O que torna a proposta uma mudança favorável?

Padrões de codificação mais regulares podem ser usados ​​para operações selecionadas com base em um conjunto de valores constantes de cadeias; o significado da nova construção deve ser óbvio para os desenvolvedores Java.

PRINCIPAL BENEFÍCIO: Por que a plataforma é melhor se a proposta for adotada?

Desempenho potencialmente melhor para código de expedição baseado em string.

DESVANTAGENS PRINCIPAIS: Sempre há um custo.

Alguns aumentaram a complexidade de implementação e teste para o compilador.

ALTERNATIVAS: Os benefícios e vantagens podem ser obtidos de alguma maneira sem uma mudança de idioma?

Não; testes encadeados if-then-else para igualdade de string são potencialmente caros e a introdução de uma enumeração para suas constantes comutáveis, uma por valor de interesse de string, adicionaria outro tipo a um programa sem uma boa causa ...


a parte em negrito é bastante surpreendente
Simon Bergot

1
@Simon bem para mim, pessoalmente, é tratado como tratamento indireto: "Perderemos a concorrência para o C # se continuarmos com as formas pré-Java5 de lidar com considerações como essa". :) Para obter um exemplo de "maneiras pré-Java5", consulte JDK-1223179: ligue as strings - enviadas em 1995 e fechadas rapidamente como Won't Fix : "Não prenda a respiração. Nada parecido com isso está em nossos planos . "
Gnat #

Obrigado, muito interessante ver as razões apresentadas na proposta. Ainda parece errado dizer que estamos apresentando um tipo a um programa "sem uma boa causa" - somos programadores OO! :)
anotherdave

5
O @anotherdave "orientado a objetos" justifica a introdução de tipos somente quando estes servem a propósitos significativos. Aparentemente, a opinião prevalecente no JCP Descobriu-se que usando enums como invólucros sem cérebro para constantes de corda em interruptor não se qualifica como significativa
mosquito

1
Uau, estou surpreso (em um bom sentido) ao ver a proposta oficial combatendo ativamente o tipo inchaço. Isso é refrescante. O tipo inchaço é um enorme problema em Java.
Ben Lee

7

Além de tornar o código mais legível, há potenciais ganhos de desempenho em relação às if/else ifcomparações. Se a mudança vale a pena depende de quantas comparações você faria. Uma chave de seqüência será emitida como duas instruções de chave separadas. O primeiro opera com códigos de hash, então tende a ser um lookupswitch, gerando O(log n)complexidade. O segundo é sempre perfeito O(1) tableswitch, então a complexidade combinada é quieta O(log n). Uma cadeia de if/else ifdeclarações única e linear daria uma O(n)complexidade um pouco pior .

Se você estiver comparando mais do que, digamos, três strings, então a switché provavelmente mais legível e compacto. Provavelmente, terá um desempenho melhor, embora você não note uma diferença, a menos que esteja fazendo um grande número de comparações em um caminho de código ativo.


1
Eu estava mais perguntando, no entanto, por que eu usaria um interruptor em uma string em vez de um enum. Eu consideraria uma if/elseprática ruim de grandes blocos, mas, no momento, não teria muitos motivos para usá-la.
precisa

Mas, então, um mapa em combinação com o padrão de comando seria mesmo render mais legibilidade com a mesma complexidade, porque você tem o tipo extra de comando
SpaceTrucker

3

A troca de strings pode ser usada quando seus enumvalores vêm de fora, ou seja, armazenados em um banco de dados.

Outra coisa notável no JDK 7 switché que é muito mais perfomanto que if-elseconstruções.

E um bom caso de uso para sequências rápidas switches poderia ser a análise de fluxo JSON / XML quando você precisar fazer várias alternâncias nos tipos de nó e atributo. Não consigo pensar em nenhuma opção melhor para isso.


1
"Mudar para strings é insubstituível quando seus valores de enum vêm de fora, ou seja, armazenados em um banco de dados.": Você pode elaborar isso? As strings na instrução switch são codificadas: assim que as strings no banco de dados são alteradas, seu código fica desatualizado.
Giorgio

Bem, você está correto - enums pode ser usado neste caso devido à natureza estática do Java. Quando eu estava escrevendo isso, estava pensando em um Rolede uma biblioteca de segurança que geralmente é fornecida como uma classe e não pode ser inserida enum. Outro caso é um código Java / Groovy compilado dinamicamente - nessa situação, que é rara, as alternâncias de string podem ser uma opção melhor.
Andrey Chaschev

2

Simplicidade

As strings no suporte do Switch são úteis para processar dados sem conversão em enum ou if-elselógica. Às vezes, é mais fácil ligar o String.

Da proposta de recurso na lista de discussão JDK 7 (projeto Coin) ( resposta @gnat )

a introdução de uma enumeração para suas constantes comutáveis, uma por valor de sequência de interesse, adicionaria outro tipo a um programa sem uma boa causa ...

Versão If-Else

Isso é curto, mas muitos if'ssão difíceis de ler. E isso é lento.

if (color.equals("red")) {
    System.out.println("Color is Red");
} else if (color.equals("green")) {
    System.out.println("Color is Green");
} else {
    System.out.println("Color not found");
}

Versão enum

Enums precisam ser definidas, isso é bom, mas às vezes não é necessário.

enum Color {RED, GREEN}

Processando como de costume

try {
    switch (Color.valueOf(color)) {
        case RED:
            System.out.println("Color is Red");
            break;
        case GREEN:
            System.out.println("Color is Green");
            break;
    }
} catch (IllegalArgumentException e) {
    System.out.println("Color not found");
}

JDK 7 - Strings no switch Statements version

Podemos processar sem converter e definir tipos adicionais.

switch (color) {
    case "red":
        System.out.println("Color is Red");
        break;
    case "green":
        System.out.println("Color is Green");
        break;
    default:
        System.out.println("Color not found");
}

7
Porém, isso não aborda a questão: por que você usaria cadeias de caracteres em vez de enumerações aqui?
Dave Newton

0

A maioria das melhorias em qualquer idioma é para facilitar a leitura do código. Eu prefiro código legível do que fantasia a qualquer dia.

Você pode não acreditar nisso, mas tente:

public enum JettStaff {
  ADRIAN("Adrian German") {
    public String toString() {
      return name + " (dgerman@indiana.edu)";
    }
  },
  ARJIT("Arjit Sengupta") {
    public String toString() {
      return name + " (asengupt@indiana.edu)";
    }
  },

  // and on for the rest...

  private String name;

  public JettStaff(String n) { this.name = n; }
}

JettStaff x = JettStaff.SUZANNE;
System.out.println(x);

Não estou claro no seu exemplo de código x nos seus comentários acima. Você quer dizer o Enum como um exemplo de algo difícil de ler?
precisa


2
Isso é muito artificial; você está fingindo que o enum não teria um campo de email ou que isso não seria uma classe.
Dave Newton

4
@ user2860598 Se você está tentando fazer um argumento, use um exemplo que seja relevante. Também não aborda o dedilhado de gordura uma constante de string.
Dave Newton

1
@ user2860598 A resposta que você vinculou é dizer que foram introduzidas e que anteriormente elas poderiam ser "aproximadas" com um Enum. Meu argumento era que o uso do Enum ainda parece preferível, mesmo com a introdução deles.
precisa

0

Enums são ótimas e você deve usá-las em vez de Strings quando tiver a capacidade de fazê-lo. Mas há momentos em que você simplesmente não pode, por exemplo, quando precisa trabalhar com algum objeto externo vindo de fora do Java. Imagine que você precisa analisar algo. Como resposta do servidor, configuração, arquivo de log ou algo semelhante: você tem várias opções que procura e não há como essas enumerações. Então, em Java <7, você ficaria preso a um monte de

  if (something.equals("foo")) {
    // foo processing
  } else 
  if (something.equals("bar")) {
   // bar processing
  }

Você ainda pode usar enumerações neste caso, apenas tentando obtê-las pelos nomes e / ou fornecendo a rotina String-> Enum personalizada, mas às vezes não é possível ou não é prático (ou seja, quando você precisa criar muitas enumerações)

TLDR : você absolutamente deve usar Enums quando estiver trabalhando exclusivamente com código Java, mas nem sempre é possível com objetos externos. Espero que minha explicação faça sentido.


Se você está lidando com dados externos e já sabe o suficiente para saber o que precisa em suas ifdeclarações, então deve encerrá-las de qualquer maneira , o que significa que você ainda pode usar enumerações ou um padrão de comando etc.
Dave Newton

@DaveNewton sim, você ainda pode usar enumerações, mas como afirmei na minha resposta, às vezes não é prático, como no caso em que você acabaria criando uma série de enumerações para ser usado apenas uma vez no código durante a análise.

@dimoniy Mas se você tivesse que criar centenas de valores de Enum, isso não significaria que, com uma opção alternativa, você teria centenas de declarações de casos? Se houver muitas variáveis, eu definitivamente preferiria a segurança de tipo de enumerações.
precisa

0

Não concordo com a opinião de que é um código mais limpo e legível quando você usa Stringsdeclarações de opção e acha que é uma má prática de programação. Se você alterar o valor que você usa para armazenar, precisará alterá-lo a cada opção ou se for o caso. Isso não é bom, pois você está colocando valores codificados em cada código do seu código. O que você fará se um dia decidir mudar um desses valores codificados? Pesquise e substitua todas as cópias?

Se você tiver alguns valores codificados que executa as instruções if-elseif, o uso de valores primitivos constantes para eles é muito melhor antes do Java 1.5, apenas porque traz segurança de tipo.

OK, haverá situações em que você obterá valores de String (de solicitação HTTP, arquivos etc.) e convertê-los para os valores primitivos é uma dor de cabeça. MasEnum s fazer um bom trabalho neste momento. Porque quando você deseja alterar o valor armazenado no Enum, basta alterá-lo quando declarar. Não há necessidade de alterar mais nada no seu código. (É claro que você precisa alterar os valores armazenados em outro lugar).

É claro que, se você está apenas implementando um código sujo e preguiçoso, é perfeito. Você não deseja envolver a codificação de muitos Enums, mas em um software complexo de grande escala que o matará.


-1

Se você souber quais informações estão chegando e que só podem ser de cinco estados, use um Enum . No entanto, se os estados possíveis puderem ser acima de 9000 e você precisar encontrar apenas 42, usar um comutador será melhor porque você não deseja digitar todos esses estados.

Um Enum tende a ser a escolha da maioria na maioria das circunstâncias, a menos que os possíveis estados sejam desconhecidos ou existam muitos e você se preocupe apenas com alguns.

Mas por que eles o introduziram agora? Foi apenas uma mudança que permitiu um código mais limpo.

Na versão 1.5, eles também permitiam a criação de corpos personalizados para as Enums.


Mas você não atribuiria apenas os outros 8958 valores possíveis ao único estado Enum?
precisa

@anotherdave Isto é onde a defaultem switchvem para jogar. Eu não sei se você pode ter um estado padrão Enum, a menos que você faça um estado padrão, mas esse código fica inchado, enquanto a switché muito mais limpo de usar.

3
Parece estranho dizer que um UNKNOWNestado em um Enum está inchado, mas um defaultcaso em um switch não está.
precisa
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.