O Java 11 não apresentou nenhum recurso inovador, mas contém várias gemas das quais você talvez ainda não tenha ouvido falar. Já olhou o mais recente em String , Optional , Collection e outros cavalos de trabalho? Caso contrário, você chegou ao endereço: hoje veremos 11 jóias escondidas do Java 11!
Inferência de tipo para parâmetros lambda
Ao escrever uma expressão lambda, você pode escolher entre especificar tipos explicitamente e ignorá-los:
Function<String, String> append = string -> string + " "; Function<String, String> append = (String s) -> s + " ";
O Java 10 apresentou var , mas não pôde ser usado em lambdas:
No Java 11 já é possível. Mas porque? Não parece que var deu mais do que apenas um passe de tipo. Embora este seja o caso, o uso de var tem duas vantagens menores:
- torna o uso de
var mais universal, removendo a exceção à regra - permite adicionar anotações ao tipo de parâmetro sem recorrer ao uso de seu nome completo
Aqui está um exemplo do segundo caso:
List<EnterpriseGradeType<With, Generics>> types = ; types .stream()
Embora a mistura de tipos derivados, explícitos e implícitos em expressões lambda da forma (var type, String option, index) -> ... possa ser implementada, mas ( na estrutura do JEP-323 ) este trabalho não foi realizado. Portanto, é necessário escolher uma das três abordagens e aderir a ela para todos os parâmetros da expressão lambda. A necessidade de especificar var para todos os parâmetros para adicionar anotação para um deles pode ser um pouco irritante, mas geralmente suportável.
Processamento de fluxo de strings com 'String::lines'
Tem uma sequência de várias linhas? Deseja fazer algo com cada linha? Então String::lines é a escolha certa:
var multiline = "\r\n\r\n\r\n"; multiline .lines()
Observe que a linha original usa os delimitadores \r\n Windows e, embora eu esteja no Linux, lines() ainda a quebrou. Isso se deve ao fato de que, apesar do sistema operacional atual, esse método interpreta \r , \n e \r\n como quebras de linha - mesmo se elas estiverem misturadas na mesma linha.
Um fluxo de linhas nunca contém os próprios separadores de linhas. As linhas podem estar vazias ( "\n\n \n\n" , que contém 5 linhas), mas a última linha da linha original será ignorada se estiver vazia ( "\n\n" ; 2 linhas). (Observação pelo tradutor: é conveniente que eles tenham line , mas que tenham string , e nós temos as duas.)
Diferente da split("\R") , as lines() preguiçosas e, cito , "fornecem melhor desempenho [...] procurando mais rapidamente novas quebras de linha". (Se alguém desejar registrar uma referência no JMH para verificação, informe-me). Também reflete melhor o algoritmo de processamento e usa uma estrutura de dados mais conveniente (fluxo em vez de matriz).
Removendo o espaço em branco com 'String::strip' etc.
Inicialmente, String tinha um método de remoção para remover espaços em branco, que era considerado tudo com códigos até U+0020 . Sim, BACKSPACE ( U+0008) é um espaço em branco como BELL ( U+0007 ), mas o LINE SEPARATOR ( U+2028 ) não é mais considerado como tal.
O Java 11 introduziu o método strip , cuja abordagem tem mais nuances. Ele usa o Character::isWhitespace do Java 5 para determinar o que exatamente precisa ser removido. A partir de sua documentação , é claro que isso:
SPACE SEPARATOR , SPACE SEPARATOR LINE SEPARATOR , LINE SEPARATOR PARAGRAPH SEPARATOR , mas não um espaço inextricávelHORIZONTAL TABULATION ( U+0009 ), LINE FEED ( U+000A ), VERTICAL TABULATION ( U+000B ), FORM FEED ( U+000C ), CARRIAGE RETURN ( U+000D )FILE SEPARATOR ( U+001C ), GROUP SEPARATOR ( U+001D ), RECORD SEPARATOR ( U+001E ), UNIT SEPARATOR ( U+001F )
Com a mesma lógica, existem mais dois métodos de limpeza, stripLeading e stripTailing , que fazem exatamente o que é esperado deles.
E, finalmente, se você só precisa descobrir se a linha fica vazia depois de remover o espaço em branco, não há realmente necessidade de excluí-la - basta usar isBlank :
" ".isBlank();
Repetindo strings com 'String::repeat'
Capte a ideia:
Etapa 1: Vigiando o JDK

Etapa 2: Localizando perguntas relacionadas ao StackOverflow

Etapa 3: chegando com uma nova resposta com base em alterações futuras

Etapa 4: ????
Etapa 4: Lucro

Como você pode imaginar, String possui um novo método repeat(int) . Funciona exatamente de acordo com as expectativas e há pouco a discutir.
Criando caminhos com 'Path::of'
Eu realmente gosto da API do Path , mas a conversão de caminhos entre diferentes modos de exibição (como Path , File , URL , URI e String ) ainda é irritante. Este ponto se tornou menos confuso no Java 11, copiando dois métodos Paths::get para Path::of methods:
Path tmp = Path.of("/home/nipa", "tmp"); Path codefx = Path.of(URI.create("http://codefx.org"));
Eles podem ser considerados canônicos, pois os dois métodos antigos Paths::get usam novas opções.
Lendo e gravando arquivos com 'Files::readString' e 'Files::writeString'
Se eu precisar ler de um arquivo grande, normalmente uso o Files::lines para obter um fluxo lento de suas linhas. Da mesma forma, para registrar uma grande quantidade de dados que não podem ser armazenados inteiramente na memória, eu uso o Files::write passando-os como Iterable<String> .
Mas e o caso simples quando quero processar o conteúdo de um arquivo como uma única linha? Isso não é muito conveniente, pois o Files::readAllBytes e as variantes apropriadas do Files::write operam em matrizes de bytes.
E, em seguida, o Java 11 aparece, adicionando readString e writeString aos Files :
String haiku = Files.readString(Path.of("haiku.txt")); String modified = modify(haiku); Files.writeString(Path.of("haiku-mod.txt"), modified);
Claro e fácil de usar. Se necessário, você pode passar o conjunto de readString para readString e, em writeString também uma matriz OpenOptions .
E / S vazia com 'Reader::nullReader' , etc.
Precisa de um OutputStream que não OutputStream lugar algum? Ou um InputStream vazio? E o Reader e o Writer que não fazem nada? O Java 11 tem tudo:
InputStream input = InputStream.nullInputStream(); OutputStream output = OutputStream.nullOutputStream(); Reader reader = Reader.nullReader(); Writer writer = Writer.nullWriter();
(Nota do tradutor: no commons-io do Apache, essas classes existem desde 2014).
No entanto, estou surpreso - é null realmente o melhor prefixo? Não gosto de como é usado para significar "ausência intencional" ... Talvez seja melhor usar noOp ? (Nota do tradutor: provavelmente esse prefixo foi escolhido devido ao uso comum de /dev/null .)
{ } ~> [ ] com 'Collection::toArray'
Como você converte coleções em matrizes?
A primeira opção, objects , perde todas as informações sobre os tipos e, portanto, está em andamento. E o resto? Ambos são volumosos, mas o primeiro é mais curto. O último cria uma matriz do tamanho necessário, para que pareça mais produtivo (ou seja, "parece mais produtivo", veja credibilidade ). Mas é realmente mais produtivo? Não, pelo contrário, é mais lento (no momento).
Mas por que eu deveria me importar com isso? Não existe uma maneira melhor de fazer isso? No Java 11, existem:
String[] strings_fun = list.toArray(String[]::new);
Uma nova variante de Collection::toArray , que aceita IntFunction<T[]> , ou seja, uma função que recebe o tamanho da matriz e retorna uma matriz do tamanho necessário. Ele pode ser expresso brevemente como uma referência a um construtor do formato T[]::new (para um T bem conhecido).
Fato interessante: a implementação padrão da Collection#toArray(IntFunction<T[]>) sempre passa 0 para o gerador de array. Inicialmente, decidi que essa solução era baseada no melhor desempenho para matrizes de comprimento zero, mas agora acho que o motivo pode ser que, para algumas coleções, calcular o tamanho possa ser uma operação muito cara e você não deva usar essa abordagem na implementação padrão da Collection . No entanto, implementações de coleções específicas, como ArrayList , podem alterar essa abordagem, mas não são alteradas no Java 11. Não vale a pena, eu acho.
Verificação de ausência com 'Optional::isEmpty'
Com o uso abundante do Optional , especialmente em grandes projetos, onde você frequentemente encontra uma abordagem não Optional , é necessário verificar se ele tem um valor. Existe um método Optional::isPresent para isso. Mas com a mesma frequência, você precisa saber o oposto - esse Optional vazio. Não tem problema, basta usar !opt.isPresent() , certo?
Obviamente, é possível assim, mas quase sempre é mais fácil entender a lógica if sua condição não for invertida. E, às vezes, o Optional aparece no final de uma longa cadeia de chamadas e, se você precisar checar por nada, então precisa apostar ! no começo:
public boolean needsToCompleteAddress(User user) { return !getAddressRepository() .findAddressFor(user) .map(this::canonicalize) .filter(Address::isComplete) .isPresent(); }
Nesse caso, pule ! muito facil A partir do Java 11, há uma opção melhor:
public boolean needsToCompleteAddress(User user) { return getAddressRepository() .findAddressFor(user) .map(this::canonicalize) .filter(Address::isComplete) .isEmpty(); }
Invertendo predicados com 'Predicate::not'
Falando em inverter ... A interface do Predicate possui um negate instância negate : retorna um novo predicado que executa a mesma verificação, mas inverte o resultado. Infelizmente, eu raramente consigo usá-lo ...
O problema é que raramente tenho acesso à instância do Predicate . Mais frequentemente, quero obter essa instância por meio de um link para um método (e invertê-lo), mas, para que isso funcione, o compilador deve saber o que levar a referência ao método - sem ele, ele não pode fazer nada. E é exatamente isso que acontece se você usar a construção (String::isBlank).negate() : o compilador não sabe mais o que String::isBlank deve estar nisso e desiste. Uma casta especificada corretamente corrige isso, mas a que custo?
Embora exista uma solução simples. Não use o negate instância negate , mas use o novo método estático Predicate.not(Predicate<T>) do Java 11:
Stream .of("a", "b", "", "c")
Já está melhor!
Expressões regulares como um predicado com 'Pattern::asMatchPredicate'
Existe uma expressão regular? Precisa filtrar dados nele? Que tal isso:
Pattern nonWordCharacter = Pattern.compile("\\W"); Stream .of("Metallica", "Motörhead") .filter(nonWordCharacter.asPredicate()) .forEach(System.out::println);
Fiquei muito feliz em encontrar esse método! Vale a pena acrescentar que este é um método do Java 8. Opa, eu perdi então. O Java 11 adicionou outro método semelhante: Pattern::asMatchPredicate . Qual a diferença?
asPredicate verifica se a sequência ou parte da sequência corresponde ao padrão (funciona como s -> this.matcher(s).find() )asMatchPredicate verifica se a sequência inteira corresponde ao padrão (funciona como s -> this.matcher(s).matches() )
Por exemplo, temos uma expressão regular que verifica os números de telefone, mas não contém ^ e $ para rastrear o início e o fim de uma linha. Em seguida, o código a seguir não funcionará conforme o esperado:
prospectivePhoneNumbers .stream() .filter(phoneNumberPatter.asPredicate()) .forEach(this::robocall);
Você percebeu um erro? Uma linha como " -152 ? +1-202-456-1414" será filtrada porque contém um número de telefone válido. Por outro lado, Pattern::asMatchPredicate não permitirá isso, porque a cadeia inteira não corresponderá mais ao padrão.
Auto-teste
Aqui está uma visão geral de todas as onze pérolas - você ainda se lembra do que cada método faz? Nesse caso, você passou no teste.
- em
String :
Stream<String> lines()String strip()String stripLeading()String stripTrailing()boolean isBlank()String repeat(int)
- no
Path :
static Path of(String, String...)static Path of(URI)
- em
Files :
String readString(Path) throws IOExceptionPath writeString(Path, CharSequence, OpenOption...) throws IOExceptionPath writeString(Path, CharSequence, Charset, OpenOption...) throws IOException
- em
InputStream : static InputStream nullInputStream() - em
OutputStream : OutputStream static OutputStream nullOutputStream() - no
Reader : Reader static Reader nullReader() - no
Writer : static Writer nullWriter() - na
Collection : T[] toArray(IntFunction<T[]>) - em
Optional : boolean isEmpty() - no
Predicate : Predicate static Predicate<T> not(Predicate<T>) - em
Pattern : Predicate<String> asMatchPredicate()
Divirta-se com o Java 11!