Dicas para jogar golfe em Java


86

Existem atalhos úteis que podem ser usados ​​em Java?

Como mostrado abaixo, importjá adiciona pelo menos 17 caracteres a um programa.

import java.io.*;

Entendo que a solução simples seria usar outra linguagem, mas parece ser um desafio real reduzir os programas Java.


As dicas devem ser específicas para Java: se forem aplicáveis ​​à maioria das linguagens do tipo C, elas pertencem à lista mais geral de dicas .


9
packagepode ser pulado.
st0le

Em uma resposta, não posso simplesmente omitir as importações, supondo que elas estejam lá?
Fabricio

1
@Fabricio Não, a menos que o OP especifique isso.
precisa saber é o seguinte

32
Melhor dica sobre golfe no Java: não use. ;)
kirbyfan64sos

4
"Eu quero jogar golfe em java" boa sorte
sagiksp

Respostas:


85
  • Use o java possível mais recente. O Java 8 permite o uso de expressões lambda, portanto, se você precisar de algo parecido com objetos funcionais.

  • Defina funções reduzidas para itens que você usa muito. Por exemplo, você tem cem chamadas para exampleClassInstance.doSomething(someParameter), defina uma nova função void d(ParameterType p){exampleClassInstance.doSomething(p)}e use-a para economizar alguns caracteres.

  • Se você estiver usando um nome longo específico de classe mais de uma vez, como

    MyEventHandlerProxyQueueExecutorServiceCollectionAccessManagerFactory

    em vez disso, defina uma nova classe:

    class X extends MyEventHandlerProxyQueueExecutorServiceCollectionAccessManagerFactory{}

    Se você estiver usando apenas um método específico dessa classe (mas ainda precisar instancia-lo), poderá definir uma versão reduzida dentro da nova classe ao mesmo tempo.

  • Use os parâmetros do tipo de função para encurtar as coisas, sempre que possível, assim:

    <T>void p(T o){System.out.println(o);}
  • Use em for(;;)vez de while(true).

  • Não use modificadores de acesso, a menos que seja absolutamente necessário.

  • Não use finalpara nada.

  • Nunca coloque um bloco depois de um forloop (mas um loop foreach for(x:y)é diferente). Instruções adicionais devem ser colocadas dentro da forprópria instrução, como for(int i=0;i<m;a(i),b(++i))c(i);.

  • Use atribuição em linha, incremento, instanciação. Use classes inline anônimas, quando apropriado. Use lambdas, se possível. Aninhar chamadas de função. É garantido que algumas funções retornam seu objeto pai, mas essas são realmente destinadas a serem encadeadas.

  • Seu mainmétodo throws Exceptions, não os pega.

  • Erroré mais curto que Exception. Se, por algum motivo, você realmente precisar throwenviar mensagens para a pilha, use um Error, mesmo que seja uma situação perfeitamente normal.

  • Se alguma condição exigir rescisão imediata, use em int a=1/0;vez de throw null;ou System.exit(0);. Em tempo de execução, isso gera um ArithmeticException. Se você já possui uma variável numérica no seu código, use-a. (Se você já possui import static java.lang.System.*;, vá com exit(0);.)

  • Em vez de implementar interfaces, como List<E>, estenda uma classe filho imediata (ou não tão imediata, se houver alguma vantagem em fazê-lo), como AbstractList<E>, que fornece implementações padrão da maioria dos métodos e requer apenas a implementação de algumas peças-chave.

  • Escreva seu código primeiro à mão, com novas linhas, recuo e nomes de variáveis ​​completos. Depois de ter o código em funcionamento, você pode encurtar nomes, mover declarações e adicionar métodos de atalho. Ao escrevê-lo por muito tempo, você terá mais oportunidade de simplificar o programa como um todo.

  • Compare otimizações alternativas a um pedaço de código, porque a estratégia mais ideal pode mudar drasticamente com alterações muito pequenas no código. Por exemplo:

    • Se você tiver apenas duas chamadas para Arrays.sort(a), a maneira mais eficiente de fazê-lo é chamá-lo com seu nome completo java.util.Arrays.sort(a),.
    • Com três ou mais chamadas, é mais eficiente adicionar um método de atalho void s(int[]a){java.util.Arrays.sort(a);}. Ainda deve usar o nome completo nesse caso. (Se você precisar de mais de uma sobrecarga, provavelmente está fazendo errado.)
    • No entanto, se seu código também precisar copiar uma matriz em algum momento (geralmente feito com um forciclo curto no golfe, na ausência de um método de biblioteca de fácil acesso), você poderá tirar proveito da Arrays.copyOftarefa. Quando mais de um método é usado e há 3 ou mais chamadas, fazer import static java.util.Arrays.*;é a maneira mais eficiente de se referir a esses métodos. Depois disso, somente se você tiver mais de 8 chamadas separadas, sortdeverá usar um método de atalho para isso e apenas em 5 ou mais chamadas é necessário um atalho copyOf.

    A única maneira real de realizar essa análise no código é realmente realizar modificações potenciais nas cópias do código e comparar os resultados.

  • Evite usar o someTypeValue.toString();método, basta anexar someTypeValue+"".

  • Se você precisar de janelas, não use o Swing, use AWT (a menos que você realmente precise de algo do Swing). Compare import javax.swing.*;e import java.awt.*;. Além disso, componentes do balanço têm um Janexado ao seu nome ( JFrame, JLabel, etc), mas componentes AWT não ( Frame, Label, etc)


43

Use em interfacevez de class.

No java 8, métodos estáticos foram adicionados às interfaces. Nas interfaces, todos os métodos são públicos por padrão. Consequentemente

class A{public static void main(String[]a){}}

agora pode ser reduzido para

interface A{static void main(String[]a){}}

o que é obviamente mais curto.

Por exemplo, usei esse recurso no Hello, World! desafio.


8
Eu não sabia disso! +1, bom truque
HyperNeutrino 14/02

Yay, menos clichê!
CalculatorFeline

3
Eu tenho que discordar parcialmente (também, eu venci você no desafio "Olá, mundo!", Usando essa técnica).
Olivier Grégoire

37

Com varargs, você pode "converter" um parâmetro em uma matriz do mesmo tipo:

void f(String...x){
    x=x[0].split("someregex");
    // some code using the array
}

ao invés de

void f(String s){
    String[]x=s.split("someregex");
    // some code using the array
}

31

Com uma importação estática :

import static java.lang.System.out;
// even shorter (thanks to Johannes Kuhn):
import static java.lang.System.*;

você pode salvar alguns clichês mais tarde, mas precisa de várias invocações para obter um retorno:

public static void main (String[] args) {
    out.println ("foo");    
    out.println ("bar");    
    out.println ("baz");    
}

8
: O. Você consegue fazer isso?! E todo esse tempo eu pensei que isso era impossível Java!
Justin

12
você pode até usar import static java.lang.System.*.
Johannes Kuhn

1
Eu sei que esta é uma resposta de idade, mas em Java 10, agora você pode fazer var o=System.out;o que só deve ser usado duas vezes antes que compensa
Luke Stevens

@LukeStevens: Bem, talvez você encontre outras melhorias possíveis no Java10 e forme uma resposta separada em torno do Java10?
usuário desconhecido

1
@LukeStevens Funcionaria var o=System.out.println?
MilkyWay90 15/03

25

O argumento para mainnão precisa ser chamado args, e você pode cortar alguns espaços em branco:

public static void main(String[]a){}

vai fazer muito bem.


1
As respostas precisam incluir a função principal se ela não declarar explicitamente para escrever um programa completo? Eu tenho usado expressões lambda como respostas.
Makotosan

3
@ Makotosan Não, eles não; Lambdas geralmente são boas.
Daniero 23/03

21

Se você precisar usar as expressões booleanas trueou false, substitua-as por 1>0e 1<0respectivamente.

Por exemplo:

boolean found=false;
for(i=0; i<10; i++) if(a[i]==42) found=true;

Este exemplo de pesquisa linear pode ser reduzido para

boolean f=1<0;
for(i=0;i<10;)if(a[i++]==42)f=1>0;

11
Se você precisar de muito true/false, basta adicionar boolean t=1>0,f=1<0;. Em vez de 1>0, use te salve dois caracteres por uso. O 1>0método de pagamento sobre pagamento é de 10 usos.
Geobits 11/03/14

24
@ Geobits: boolean t=1>0,f=!t;- um char mais curto!
bobbel

6
O exemplo não é realmente bom. Neste caso e em muitos outros (!) Você pode evitar o uso true/ falsediretamente de qualquer maneira: f|=a[i++]==42;economiza bastante.
Ingo Bürk 27/09/14

@ IngoBürk True. Quando eu estava escrevendo isso, eu estava pensando principalmente nas funções de biblioteca que usam boolean, mas como não consegui encontrar nenhum exemplo no momento em que escrevi (normalmente não codigo em Java), acabei de escrever um exemplo simples.
ace_HongKongIndependence

1
@Geobits não muito familiarizados com Java, mas você poderia apenas definir 1 e usar t e t (novamente eu não sei Java, apenas curioso)!
Albert Renshaw

20

Se você estiver usando muito algum método, atribua sua classe residente a uma variável. Por exemplo, atribua System.outa uma variável:

java.io.PrintStream o=System.out;
//now I can call o.print() or o.println() to the same effect as System.out.println()

Também para Integer.parseInt():

Integer i=1;
i.parseInt("some string");

Isso quase certamente acionará um aviso de ide sobre "acessar método estático a partir da variável"


((Integer)1).parseInt("1")funciona também
Urna de polvo mágico

5
@carusocomputing new Integer("1")é ainda mais curto. Mas o que Justin quis dizer com sua resposta é que você pode reutilizar variáveis ​​que já possui para chamadas estáticas. Como explico no final desta resposta.
Kevin Cruijssen

19

Em vez de usar a import static java.lang.System.*técnica para economizar em println()instruções, descobri que definir o método a seguir é muito mais eficaz para salvar caracteres:

static<T>void p(T p){
    System.out.println(p);
}

Isso ocorre porque pode ser invocado p(myString)e não out.println(myString)com um retorno de personagem muito mais rápido e mais dramático.


19

Isso pode parecer óbvio, mas existem opções mais curtas para algumas Mathfunções:

a=Math.max(b,c);
a=b>c?b:c;

a=Math.min(b,c);
a=b<c?b:c;

a=Math.abs(b);
a=b<0?-b:b;

a=Math.round(b);
a=(int)(b+.5);          // watch for precision loss if it matters

14

Se você precisar Integer.MAX_VALUE(2147483647), use -1>>>1. Integer.MIN_VALUE(-2147483648) está melhor escrito 1<<31.


14

Se você precisar pegar um número de um argumento (ou qualquer outra string), normalmente verá algo como:

public static void main(String[]a){
    int n=Integer.valueOf(a[0]);
    ...
}

Muitas vezes, você não precisa de um Integer. Muitos desafios não usam grandes números. Como Shorte Byteirá unbox para um int, use o mais apropriado valueOf()e salve alguns bytes.

Mantenha sua variável real como uma int, pois é mais curta que ambas bytee short:

int n=Byte.valueOf(a[0]);

Se você precisar fazer isso para vários números, poderá combinar com este método :

Byte b=1;
int n=b.valueOf(a[0]),m=b.valueOf(a[1])...

9
int n=new Byte(a[0]);é três mais curto. Se o número for maior, use long n=new Long(a[0]), ainda é melhor que ints na maioria dos casos.
Ypnypn

14

Não use public class. O método principal precisa ser público, mas sua classe não. Este código funciona:

class S{public static void main(String[]a){System.out.println("works");}}

Você pode executar java Smesmo que class Snão seja uma classe pública. ( Atualização: Eu estava usando o Java 7 quando escrevi esta dica. No Java 8, seu método principal deve estar em uma interface . No Java 5 ou 6, seu método principal deve estar em uma enumeração .)

Muitos programadores de Java não sabem disso! Cerca de metade das respostas a uma pergunta do Stack Overflow sobre main na classe não pública afirmam erroneamente que o método principal deve estar em uma classe pública. Agora você sabe melhor. Excluir o publicem public classe salvar 7 caracteres.


1
A menos que você esteja direcionando um Java antes da 1.8, a construção interface s{static void main(String[]...é mais curta. Se você deve ter um arquivo de origem compilável e o método principal. Como em uma interface Java 1.8, todos os métodos são públicos, assim você pode pular o modificador no (s) método (s).
Douglas Held

Como não usei Java recentemente, minha resposta está ficando desatualizada. Eu esqueci que as interfaces podem ter métodos em Java 8.
kernigh

Eu não aprendi isso de programação; Eu aprendi isso com o golfe :) #
482 Douglas Held

14

Algumas pequenas dicas sobre golfe com códigos

Essas dicas eram um pouco pequenas para respostas separadas, portanto, usarei essa resposta para dicas muito pequenas de codegolf que encontrei ou que surgiram e ainda não foram mencionadas nas outras dicas:

Removendo o último caractere de uma String:

// I used to do something like this:
s.substring(0,s.length()-1)     // 27 bytes

// But this is shorter:
s.replaceAll(".$","")           // 21 bytes

Em alguns casos, você sabe qual é o último caractere de antemão e também sabe que esse caractere ocorre apenas uma vez na String. Nesse caso, você pode usar .split:

// As example: "100%" to "100"
s.split("%")[0]                 // 15 bytes

Atalhos de codificação:

// When you want to get the UTF-8 bytes I used to do this:
s.getBytes("UTF-8");     // 20 bytes

// But you can also use "UTF8" for the same result:
s.getBytes("UTF8");      // 19 bytes

Todas as codificações têm um nome canônico usado na java.nioAPI, bem como um nome canônico usado nas APIs java.ioe java.lang. Aqui está uma lista completa de todas as codificações suportadas em Java. Portanto, sempre use o menor dos dois; o segundo é geralmente mais curto (como UTF-8vs utf8, Windows-1252vs Cp1252, etc.), mas nem sempre ( UTF-16BEvs UnicodeBigUnmarked).

Booleano aleatório:

// You could do something like this:
new java.util.Random().nextBoolean()     // 36 bytes

// But as mentioned before in @Geobits' answer, Math.random() doesn't require an import:
Math.random()<.5                         // 16 bytes

Primes:

Existem várias maneiras diferentes de verificar primos ou obter todos os primos, mas a resposta de @ SaraJ aqui é a mais curta. Aqui está um copiar e colar como referência:

// Check if n is a prime:
n->{int i=1;for(;n%++i%n>0;);return n==i;}

// Which can easily be modified to loop through primes:
v->{for(int n=2,i;;){for(i=1;n%++i%n>0;);if(n++==i)/*do something with prime `i` here*/;}}

NOTA: Geralmente, você pode mesclá-lo com outros loops existentes, dependendo de como deseja usá-lo, para não precisar de um método separado. Isso economizou muitos bytes nesta resposta, por exemplo.

Truncamento inteiro em vez de Math.floor / Math.ceil:

Se você estiver usando duplos / flutuadores positivos e desejar floor, não use, Math.floormas use um (int)-cast (pois o Java trunca em números inteiros):

double d = 54.99;

int n=(int)Math.floor(d);     // 25 bytes

int m=(int)d;                 // 13 bytes

// Outputs 54 for both

O mesmo truque pode ser aplicado aos duplos / flutuadores negativos que você deseja ceil:

double d = -54.99;

int n=(int)Math.ceil(d);     // 24 bytes

int m=(int)d;                // 13 bytes

// Outputs -54 for both

Use em &1vez de %2se livrar dos parênteses:

Como a Precedência do operador de &é menor que os operadores aritméticos padrão como */+-e %, em alguns casos, você pode se livrar do parêntese.

// So instead of this:
(i+j)%2     // 7 bytes

// Use this:
i+j&1       // 5 bytes

Observe que isso realmente não ajuda nas verificações booleanas, porque você ainda precisa de parênteses, elas são apenas movidas um pouco:

(i+j)%2<1    // 9 bytes
(i+j&1)<1    // 9 bytes

BigIntegers e criando variáveis ​​para chamadas de método estático:

Ao usar o BigIntegers, crie-o apenas uma vez e depois reutilize-o. Como você deve saber, o BigInteger contém campos estáticos para ZERO, ONEe TEN. Portanto, quando você usa apenas esses três, não precisa de um, importmas pode usá-lo java.Math.BigIntegerdiretamente.

// So instead of this:
import java.math.BigInteger.*;
BigInteger a=BigInteger.ONE,b=BigInteger.ZERO;                // 76 bytes

// or this:
java.math.BigInteger a=java.math.BigInteger.ONE,b=a.ZERO;     // 57 bytes

// Use this:
java.math.BigInteger t=null,a=t.ONE,b=t.ZERO;                 // 45 bytes                  

OBSERVAÇÃO: você deve usar =nullpara que tseja inicializado para poder usar t..

Às vezes, você pode adicionar vários BigIntegers para criar outro para salvar bytes. Então, digamos que você queira ter os BigIntegers 1,10,12por algum motivo:

// So instead of this:
BigInteger t=null,a=t.ONE,b=t.TEN,c=new BigInteger(12);     // 55 bytes

// Use this:
BigInteger t=null,a=t.ONE,b=t.TEN,c=b.add(a).add(a);        // 52 bytes

Como corretamente apontado nos comentários, o truque com BigInteger t=null;as chamadas de método estático também pode ser usado com outras classes.
Por exemplo, esta resposta de 2011 pode ser jogada no golfe:

// 173 bytes:
import java.util.*;class g{public static void main(String[]p){String[]a=p[0].split(""),b=p[1].split("");Arrays.sort(a);Arrays.sort(b);System.out.print(Arrays.equals(a,b));}}

// 163 bytes
class g{public static void main(String[]p){java.util.Arrays x=null;String[]a=p[0].split(""),b=p[1].split("");x.sort(a);x.sort(b);System.out.print(x.equals(a,b));}}

getBytes() ao invés de toCharArray()

Quando você deseja fazer um loop sobre os caracteres de uma String, geralmente você faz isso:

for(char c:s.toCharArray())    // 27 bytes
// or this:
for(String c:s.split(""))      // 25 bytes

Fazer um loop sobre os caracteres pode ser útil ao imprimi-los ou anexá-los a uma String ou algo semelhante.

No entanto, se você usar apenas os caracteres para alguns cálculos de número unicode, poderá substituir charpor inte AND toCharArray()por getBytes():

for(int c:s.getBytes())        // 23 bytes

Ou ainda mais curto no Java 8+:

s.chars().forEach(c->...)      // 22 bytes

No Java 10+, o loop sobre o caractere a ser impresso também pode ser feito em 22 bytes:

for(var c:s.split(""))         // 22 bytes

Item aleatório de a List:

List l=...;

// When we have an `import java.util.*;` in our code, shuffling is shortest:
return l.get(new Random().nextInt(l.size()));     // 45 bytes
return l.get((int)(Math.random()*l.size()));      // 44 bytes
Collections.shuffle(l);return l.get(0);           // 39 bytes

// When we don't have an `import java.util.*` in our code, `Math.random` is shortest:
return l.get(new java.util.Random().nextInt(l.size()));     // 55 bytes
return l.get((int)(Math.random()*l.size()));                // 44 bytes
java.util.Collections.shuffle(l);return l.get(0);           // 49 bytes

Verifique se uma String contém espaços iniciais / finais

String s=...;

// I used to use a regex like this:
s.matches(" .*|.* ")     // 20 bytes
// But this is shorter:
!s.trim().equals(s)      // 19 bytes
// And this is even shorter due to a nice feature of String#trim:
s!=s.trim()              // 11 bytes

Por que isso funciona, quando !=em Strings é procurar referência em vez de valor em Java? Porque String#trimretornará " Uma cópia dessa sequência com o espaço em branco à esquerda e à direita removido, ou essa sequência se não tiver espaço em branco à esquerda ou à direita . " Eu usei isso, depois que alguém me sugeriu isso, nesta resposta minha .

Palíndromo:

Para verificar se uma String é um palíndromo (tendo em mente os comprimentos pares e ímpares de Strings), este é o mais curto ( .containsfunciona aqui porque sabemos que a própria String e sua forma invertida têm o mesmo comprimento):

String s=...;
s.contains(new StringBuffer(s).reverse())    // 41 bytes

.contains(...)em vez de .equals(...+"")agradecer ao comentário de @assylias aqui .

Ou é 0 ou ambos são 0?

Eu acho que a maioria já conhece este: se você quiser verificar se é aou bé zero, multiplique para salvar bytes:

a==0|b==0    // 9 bytes
a*b==0       // 6 bytes

E se você quiser verificar se ambos ae bsão zero, você poderia usar um bit a bit-OR, ou adicioná-los juntos se eles são sempre positivos:

a==0&b==0    // 9 bytes
(a|b)==0     // 8 bytes (if either `a`, `b` or both can be negative)
a+b<1        // 5 bytes (this only works if neither `a` nor `b` can be negative)

Par = 1, ímpar = -1; ou vice-versa

// even = 1; odd = -1:
n%2<1?1:-1        // 10 bytes
1-n%2*2           // 7 bytes

// even = -1; odd = 1:
n%2<1?-1:1        // 10 bytes
n%2*2-1           // 7 bytes

A razão de eu adicionar este foi depois de ver k+(k%2<1?1:-1)nos esta resposta :

k+(k%2<1?1:-1)    // 14 bytes

// This would already have been shorter:
k%2<1?k+1:k-1     // 13 bytes

// But it can also be:
k%2*-2-~k         // 9 bytes

nTempos de loop no programa completo

Se tivermos um desafio em que um programa completo é obrigatório e precisamos repetir uma quantidade específica de vezes, podemos fazer o seguinte:

// instead of:
interface M{static void main(String[]a){for(int n=50;n-->0;)/*do something*/}}  // 78 bytes
// we could do:
interface M{static void main(String[]a){for(M m:new M[50])/*do something*/}}    // 76 bytes

O mesmo se aplica quando temos que usar esse intervalo como entrada:

interface M{static void main(String[]a){for(int n=new Byte(a[0]);n-->0;)/*do something*/}}  // 90 bytes
interface M{static void main(String[]a){for(M m:new M[new Byte(a[0])])/*do something*/}}    // 88 bytes

Os créditos a @JackAmmo neste comentário .

try-finalmente em vez de try-catch (exceção e) ao retornar e quando usá-lo

Se você não pode usar um, throws Exceptionmas precisa catchfazer algo antes de retornar, pode usar finally:

try{...}catch(Exception e){return ...;}    // 33 bytes
try{...}finally{return ...;}               // 22 bytes

Como exemplo de quando usar a try-catch, posso me referir a esta resposta minha (o crédito para o golfe indireto vai para @KamilDrakari ). Nesse desafio, temos que fazer um loop diagonal sobre uma matriz NxM, portanto, precisamos determinar se a quantidade de colunas ou a quantidade de linhas é a mais baixa que a máxima no loop for (o que é bastante caro em termos de bytes :) i<Math.min(a.length,a[0].length). Portanto, simplesmente capturar o ArrayIndexOutOfBoundsExceptionuso catch-finallyé mais curto que essa verificação e, assim, salva bytes:

int[] a = ...;

int r=0,i=0;for(;i<Math.min(a.length,a[0].length);)r=...i++...;return r;    // 66 bytes

int r=0,i=0;try{for(;;)r=...i++...;}finally{return r;}                      // 48 bytes

NOTA: Isso só funcionou por causa do return r;no finalmente. Fui sugerido para modificar a primeira célula, como @KamilDrakari fez em sua resposta em C # para salvar bytes. No entanto, em Java, isso significa que terei que alterá-lo para m->{try{for(int i=1;;m[0][0]=f(m[0][0],m[i][i++]));}catch(Exception e){}}(73 bytes), na verdade aumentando a contagem de bytes em vez de diminuir se eu pudesse usá-lo finally.

Math.pow (2, n)

Quando você quer um poder de 2, uma abordagem pouco inteligente é muito mais curta:

(int)Math.pow(2,n)    // 16 bytes
(1<<n)                // 6 bytes

Combinando verificações bit a bit e lógicas em vez de usar parênteses

Eu acho que agora é bem conhecido &e |pode ser usado em vez de &&e ||nas verificações lógicas Java (booleanas). Em alguns casos, você ainda gostaria de usar em &&vez de &evitar erros, como index >= 0 && array[index].doSomething. Se o &&for alterado para &aqui, ele ainda avaliará a parte em que usa o índice na matriz, causando um ArrayIndexOutOfBoundsException, portanto, o uso de &&neste caso, em vez de &.

Até agora, o básico de &&/ ||vs &/ |em Java.

Quando você deseja verificar (A or B) and C, o menor pode parecer usar os operadores bit a bit como este:

(A|B)&C    // 7 bytes

No entanto, como os operadores bit a bit têm precedência de operador sobre as verificações lógicas, você pode combinar os dois para salvar um byte aqui:

A|B&&C     // 6 bytes

Use em n+=...-nvez de(long)...

Quando você tem um tempo entre in e output em um lambda, por exemplo, ao usar Math.pow, é possível salvar um byte usando em n+=...-nvez de (long)....
Por exemplo:

n->(long)Math.pow(10,n)    // 23 bytes
n->n+=Math.pow(10,n)-n     // 22 bytes

Isso salvou um byte em esta resposta da mina , e até dois bytes, combinando -n-1a +~nem esta resposta da mina .


De maneira mais geral, para o seu último ponto, você pode acessar / chamar membros estáticos de um contexto não estático, como uma instância do objeto.
Puxa

1
Eu não entendo sua ponta do teto. Por que você gostaria de teto positive integers? Além disso, não tenho certeza se a implementação do teto funciona .
Jonathan Frech

1
since Java automatically floors on integers; Eu acho que o termo adequado é truncamento , não piso .
Jonathan Frech

1
Outra estratégia do PalíndromoString t="";for(int i=s.length();--i>=0;t+=s.charAt(i));return s.equals(t);
Roberto Graham

1
@RobertoGraham Na verdade, copiei meu código original do desafio errado. Basta s.equals(new StringBuffer(s).reverse()+"").
Kevin Cruijssen 5/10

11

Para o golfe que não requer entrada, você pode usar blocos estáticos e executá-lo sem nenhum método principal, basta compilá-lo com o Java 6.

public class StaticExample{
    static {
        //do stuff
    }
}

1
Você tentou compilar e executá-lo? Este bloco é executado quando a classe é carregada pelo carregador de classes. Mas o carregador de classes não carregará nada até conhecer uma classe com um método principal.
Cruncher

@Cruncher Você pode contornar isso sozinho, dizendo javana linha de comando / em um arquivo de manifesto qual classe carregar.
AJMansfield

6
@Cruncher, isso funcionou com o Java 6. O Java 7 mudou a maneira como funciona.
Peter Taylor

1
Lança uma exceção no final, mas funciona! Mesmo em Java 7
stommestack

2
@JopVernooij Se você não quer ter uma exceção lançada para o seu rosto, você pode System.exit (), mas você vai perder caracteres, nenhum desafio de golfe sempre pede-lhe para evitar exceções;)
Fabinout

11

Todos sabemos sobre o xor ( ^) bit a bit , mas também é um xor lógico.

Então (a||b)&&!(a&&b)simplesmente se torna a^b.

Agora podemos usar o xor.

Além disso , os operadores |e & também trabalham , basta lembrar que a precedência do operador muda.


5
Contanto que você se lembre da precedência, você pode usar & e |também. Pode ser útil se suas condições já estiverem entre parênteses ou se você já estiver trabalhando com booleanos.
Geobits

1
Se você precisa de um (muito) menor precedência, você pode usar !=em vez de ^para XOR, e ==para xnor
Cyoce

11

Você não precisa usar Character.toLowerCase(char c). Em vez disso, use (c|32). Em vez de Character.toUpperCase(char c)usar (c&~32). Isso funciona apenas com letras ASCII.


c|~32tenderia a resultar em -1 ... melhor de usar c-32.
feersum

5
@feersum Isso não funcionaria se você quisesse fazer uma letra maiúscula em maiúscula.
TheNumberOne

11

Converter String em número

Existem várias maneiras de converter uma String em um valor numérico:

String s = "12";

ABC.parseABC :

Short.parseShort(s); // 20 bytes
Integer.parseInt(s); // 20 bytes
Long.parseLong(s);   // 18 bytes

ABC.valueOf :

Short.valueOf(s);    // 17 bytes
Integer.valueOf(s);  // 19 bytes
Long.valueOf(s);     // 16 bytes

ABC.decode :

// Note: does not work for numeric values with leading zeros,
// since these will be converted to octal numbers instead
Short.decode(s);     // 16 bytes
Integer.decode(s);   // 18 bytes
Long.decode(s);      // 15 bytes

novo ABC :

new Short(s);        // 13 bytes
new Integer(s);      // 15 bytes
new Long(s);         // 12 bytes

Portanto, para jogar golfe com código, é melhor usar o construtor ao converter uma String em um valor numérico.

O mesmo se aplica a Double; Float; e Byte.


Isso nem sempre se aplica quando você pode reutilizar uma primitiva já presente como objeto.
Como exemplo, digamos que temos o seguinte código:

// NOTE: Pretty bad example, because changing the short to int would probably be shorter..
//       but it's just an example to get the point across

short f(short i,String s){
  short r=new Short(s);  // 21 bytes
  ... // Do something with both shorts
}

Você pode usar em .decodevez do construtor mais curto reutilizando o parâmetro como objeto:

short f(Short i,String s){   // Note the short parameter has changed to Short here
  short r=i.decode(s);   // 20 bytes
  ... // Do something with both shorts
}

10

Não use Random!

Em geral, se você precisar de números aleatórios, Randomé uma maneira horrível de fazer isso *. Muito melhor usar em seu Math.random()lugar. Para usar Random, você precisa fazer isso (digamos que precisamos de um int):

import java.util.*;
Random r=new Random();
a=r.nextInt(9);
b=r.nextInt(9);

Compare isso com:

a=(int)(Math.random()*9);
b=(int)(Math.random()*9);

e:

int r(int m){return(int)(Math.random()*m);}
a=r(9);
b=r(9);

O primeiro método utiliza 41+15ncaracteres ( né o número de chamadas). O segundo são 25ncaracteres e o terceiro é 43+7n.

Portanto, se você precisar apenas uma ou duas vezes, use o Math.random()método inline . Para três ou mais chamadas, você salvará usando uma função. Qualquer um salva os caracteres no primeiro uso novamente Random.


Se você já está usando Math.random()para double, lembre-se que em quatro usos, ainda é uma poupança para puxá-lo para fora em:

double r(){return Math.random();}

Para 33 caracteres, você economiza 10 em cada chamada para r()


Atualizar

Se você precisar de um número inteiro e quiser economizar na transmissão, não o faça! O Java é auto-convertido se você executar uma operação em vez de uma atribuição. Comparar:

a=(int)(Math.random()*9);
a=9;a*=Math.random();

* A menos que você precise semear o PRNG para obter resultados previsíveis. Então, não vejo muita maneira de contornar isso.



@ Quincunx True, fazer as contas para obter uma boa distribuição normal perderia todas as economias que você obtivesse. Vou apenas referir-se a isso como a exceção que confirma a regra;)
Geobits

Observe que (int)(Math.random()*9)possui um viés de módulo muito pequeno, pois Math.random()retorna 2 53 valores possíveis e 2 53 não é um múltiplo de 9. A probabilidade de cada número está dentro de 1/9 mais ou menos 5 / (9 * 2 ** 53), um erro tão pequeno, é quase exatamente 1/9.
kernigh

@ kernigh Certo, eu estava usando 9apenas como exemplo, poderia ser qualquer coisa. Estou relativamente certo de que nextInt()(ou qualquer outro Randommétodo) também tem um pequeno viés, apenas devido ao funcionamento do PRNG do Java.
Geobits

1
Algo relacionado a quando você deseja um booleano aleatório: em vez de new java.util.Random().nextBoolean()você pode usar Math.random()<.5.
Kevin Cruijssen

7

Não sei se você consideraria esse Java 'puro', mas o Processamento permite criar programas com pouca configuração inicial (concluída automaticamente).

Para saída do console, você pode ter algo tão simples quanto:

println("hi"); //done

para saída gráfica, um pouco mais:

void setup() {
  size(640,480);
}
void draw() {
  fill(255,0,0); //color used to fill shapes
  rect(50,50,25,25); //25x25 pixel square at x=50,y=50
}

1
+1 Excelente recurso! Eu vou ter certeza de brincar com isso.
19712 Rob

Tudo bem se eu adicionasse as respostas de outras pessoas a essa? Ou isso derrota o propósito de um wiki da comunidade?
Rob

2
A propósito, você nem precisa ligar size; o padrão será um quadrado de 100 por 100 pixels. Na maioria dos sistemas operacionais, o quadro em torno dele será duas vezes maior, com o quadrado centralizado e o restante da área preenchida com o conteúdo retirado da área de trabalho.
AJMansfield

1
Para saída gráfica, se você não precisar de animação, basta escrever tudo fora setup()e draw()usar o "modo estático". Você também pode usar cores hexadecimais de 6 dígitos e o intérprete as alterará, o que às vezes compensa ( #FF8000< 255,128,0), e se você estiver usando a escala de cinzas, apenas um número precisará ser especificado ( 255< 255,255,255)
quat

7

Encurtando o retorno

Você pode reduzir as instruções de retorno de strings por um byte com:

return "something";

para

return"something";

E, se você começar sua declaração de retorno entre parênteses, poderá fazer o mesmo com eles:

return (1+taxRate)*value;

para

return(1+taxRate)*value;

Eu acho que citações são consideradas parênteses? Na verdade, eu peguei isso no AppleScript, o que é engraçado, e achei que valeria a pena mencionar.


1
O mesmo se aplica aos sinais numéricos, como em return-n;vez de return -n;ou em return~n;vez de return ~n;. Bem como aspas simples, em vez de aspas duplas:return'A';
Kevin Cruijssen 21/09

1
Basicamente, funciona para qualquer coisa que não possa fazer parte de um identificador (ou seja, sem letra e sem dígito).
Pa Elo Ebermann 17/02

7

Não tenha medo de usar notação científica

Se você estiver lidando com duplos ou flutuadores, poderá usar notação científica para números. Portanto, em vez de escrever, double a=1000você pode alterá-lo double a=1e3para salvar 1 byte.


7

Tente usar em intvez deboolean

Em alguns casos, descobri que é mais curto retornar um valor inteiro de um método que normalmente retornaria um booleano, semelhante ao que pode ser feito nos programas C.

Logo de cara inté 4 bytes menor que boolean. Cada vez que você escreve, em return 0vez de return 1<0, salva 2 bytes adicionais e o mesmo por return 1 mais de return 1>0.

A armadilha aqui é que cada vez que você deseja usar o valor de retorno diretamente como um booleano, custa 2 bytes ( if(p(n))v. if(p(n)>0)). Isso pode ser compensado pelo uso da aritmética booleana. Dado um cenário artificial em que você deseja escrever

void a(int[]t){t[0]+=p(n)?10:0;}

você pode escrever

void a(int[]t){t[0]+=p(n)*10;}

para salvar 2 bytes.


6
Faço isso com bastante frequência ao jogar golfe, mas lembre-se de que o consenso geral é esse 0e 1não constitui falso / verdadeiro em Java (e o JLS também não os considera dessa maneira). Portanto, se o golfe está pedindo especificamente por verdade / falsidade, você precisa fazer um booleano (e, infelizmente, torná-lo uma booleanfunção, jogando ainda mais bytes nele).
Geobits

2
t[0]+=p(n):10?0;Isso é válido?
dorukayhan

@dorukayhan não, é para ser t[0]+=p(n)?10:0;. (
Editei

6

Se você usar enum em vez de classe , salve um caractere.

enum NoClass {
    F, G, H;    
    public static void main (String[] args) {

    }
}

Mas você precisa introduzir pelo menos uma instância enum (F, G, H neste exemplo) que precisa ser recompensada.


2
Parece que você não precisa de nenhuma instância enum. Eu fiz enum M{;public static void main(String[]a){...}sem problemas.
Danny

3
@ Danny Mas então ele não salva nenhum personagem. class M{tem exatamente o mesmo comprimento que enum M{;. Nesse caso, eu iria com o classporque é mais bonita (IMO)
Justin

1
pelo menos para mim enum{trabalhou sem ;depois; seu único IDE gemendo que há um compilador erro butthe aceita
masterX244

@ masterX244 Qual compilador / versão? O meu faz birra e não o faz.
Geobits

trabalhou em java 1.7 para mim (apareceu s, Ned para investigar causa com a atualização para 0,8 ele parou de funcionar)
masterX244

5

Quando você tem um método que deve retornar a booleanou Boolean, ou seja:

// Return true if the (non-negative) input is dividable by 5
boolean c(int i){return i%5<1;}

Você pode alterar o tipo boolean/ Booleanreturn Objectpara salvar 1 byte:

Object c(int i){return i%5<1;}

Além disso, como você deve ter notado, pode usar uma <1verificação em vez de ==0salvar um byte. Embora isso seja mais uma dica geral de código de golfe em vez de específica para Java.
Isso é usado principalmente quando o número inteiro não pode ser negativo, como verificar o comprimento:

a.length<1

ao invés de

a.length==0

1
Boa dica! Você pode adicionar outro exemplo na seção "se não puder ser negativo" para ilustrá-lo, pois c(-21)retorna truecom o atual.
Geobits

Esclarecido. Além disso, você não quer dizer em c(-20)vez de -21? -21 % 5 = 4e -20 % 5 = 0.
Kevin Cruijssen

1
Não, eu quis dizer -21. -21 % 5 != 4em Java, que é o meu ponto. O divisível por cinco função iria funcionar corretamente se o módulo sempre voltava não negativo, mas isso não acontece. Veja este exemplo de trecho .
Geobits

@ Geobits Ah, obrigado pelo exemplo. Eu quase nunca usar números negativos com %, então eu esqueci Java retorna o resto em vez do módulo, daí a diferença ..
Kevin Cruijssen

5

Como desenhar em Java ...

Aqui está a placa da caldeira de tinta GUI mais curta possível:

import java.awt.*;
static void main(String[]x){
    new Frame(){
        public void paint(Graphics g){
            // Draw your stuff here.
        }    
    }.show();
}

Golfe por 111 bytes:

import java.awt.*;static void main(String[]x){new Frame(){public void paint(Graphics g){/*CodeHere*/}}.show();}

5

Evite StringBuilders

Anexar itens a um Stringocupa muito menos bytes.

// s is a StringBuilder
s.append("Hello, World!");

// S is a String
S+="Hello, World!";

Se você precisar reverter uma sequência e imprimi-la imediatamente, use a StringBuffer.

System.out.print(new StringBuilder("Hello, World!").reverse());
System.out.print(new StringBuffer("Hello, World!").reverse()); // Note that you can omit toString() when printing a non-String object

Se você precisar reverter uma string e fazer outra coisa que não imprimi-la, use um forloop cada.

String b=new StringBuffer("Hello, World!").reverse().toString();
String B="";for(String c:"Hello, World!".split(""))B=c+B;

3
Um loop foreach é mais curto do que StringBufferpara reverter seqüências. String b="";for(char c:"Hello, World!".toCharArray()){b=c+b;}
Puxa

1
Você também deve remover o {}loop foreach se quiser usar esse método.
Geobits

1
Salve 2 bytes usando em String s:"".split("")vez de char c:"".toCharArray().
22616 charlie

Se você java.util.stream.Streamjá importou e se precisa encadear outra chamada para o resultado (como B.chartAt(42)) ou se apenas precisa passar o resultado para uma função (como f(B)), usar for(:)é igual a Stream.of("Hello, World!".split("")).reduce("",(a,b)->b+a).
22616 charlie

Ambas as linhas no seu exemplo com o for-each podem ser jogadas de golfe. O primeiro pode se tornar: String b=new StringBuffer("Hello, World!").reverse()+"";( .toStringsubstituído por +""), e sua segunda linha pode se tornar: String B="";for(String c:"Hello, World!".split(""))B=c+B;( charpara Stringe .toCharArray()para .split("")).
Kevin Cruijssen

5

Use Java 10's var

Se você definir uma única variável de um tipo específico, use var.

Exemplos

var i=0;                        // int
var l=0L;                       // long
var s="";                       // String
var a=new int[]{1,2,3};         // int[]
var i=java.math.BigInteger.ONE; // BigInteger
var m=new java.util.HashMap();  // HashMap
var i=3+"abc".length()          // int
var a="a b c".split(" ");       // String[]
for(var a:"a b c".split(" "))   // String

Não pode ser usado em nenhum dos seguintes exemplos

var não pode ser usado em muitos exemplos

var i=1,j=2;           // only one variable is accepted at a time
var a={1,2,3};         // arrays must be explicitly declared
var f=a->a+" ";        // can't know what type a is.
var f=String::replace; // method references aren't properly implied (weirdly, though)

RE por que isso não funciona com referências de método, observe que existem interfaces funcionais padrão para apenas um pequeno conjunto de assinaturas (e os métodos podem gerar exceções verificadas).
Jakob


4

Na maioria dos casos, seu programa será de thread único, ou seja, terá apenas um thread em execução. Você pode explorar esse fato returnusando o método principal quando precisar sair instantaneamente.

static void main(String[]a){if(condition)return;}

Compare-o com o encerramento "adequado" do programa:

static void main(String[]a){if(condition)System.exit(0);}

Ou apontando para null:

static void main(String[]a){if(condition)throw null;}

Ou dividindo por 0:

static void main(String[]a){if(condition)int A=1/0;}

4

Às vezes, uma única instrução for-loop pode ser substituída. Considere o seguinte código:

int m(int x){int i=1;for(;x%++i==0;);return i;}

Este é um loop for simples, que é uma solução para esta pergunta .

Como sabemos que inão será grande o suficiente para causar erros no StackOverflow, podemos substituir o loop for por recursão:

int m(int x,int i){return x%++i>0?i:m(x,i);}

Podemos simular um loop usando um operador ternário na declaração de retorno para causar recursão.

Essa redução é bastante específica, mas posso imaginar mais situações em que isso seria útil.


4

Usando ...(varags) como parâmetro

Em alguns casos, é mais curto usar um varargs Java como parâmetro em vez de outros frouxos.
Por exemplo:

// Example input/output: 5, 4, 3 -> 60000
int calculateVolumeInLiters(int width, int height, int depth){
  return width * height * depth * 1000;
}

Seria golfe por mais para isso:

int c(int w,int h,int d){return w*h*d*1000;} // 44 bytes

Mas pode ser jogado um byte adicional para isso:

int c(int...a){return a[0]*a[1]*a[2]*1000;}  // 43 bytes

Observe que todos os três números inteiros são acessados ​​apenas uma vez no próprio método. Como inté bastante curto, só é benéfico se você os usar apenas uma vez dentro do método e tiver três ou mais deles como parâmetro.

Com parâmetros mais longos, isso geralmente é mais útil. Por exemplo, esta foi minha resposta original para esse desafio (calcular ocorrências do caractere de entrada na string de entrada):

// Example input/output: tttggloyoi, t -> 3

int c(String a,char b){return a.replaceAll("[^"+b+"]","").length();} // 68 bytes

E eu fui recomendado a jogar com isso:

int c(String a,char b){return a.split(b+"").length-1;}               // 54 bytes

Mas acabei jogando isso usando ...:

int c(String...a){return a[0].split(a[1]).length-1;}                 // 52 bytes

NOTA: Se a pergunta / desafio solicitar uma entrada flexível, ela ...poderá ser reduzida para, é []claro. Se a pergunta / desafio solicitar especificamente, digamos, três Stringentradas e não permitir um Stringarray contendo três valores, você poderá usar em String...vez de String a,String b,String c.


2
Você não pode usar um em String[]vez de usar varargs? (economiza mais 1 byte)
Kritixi Lithos 24/03

@KritixiLithos Hmm .. good point. Mas isso depende principalmente de quão flexível é a contribuição para o desafio. Se qualquer formato de entrada for permitido, isso seria realmente mais curto. Vou adicionar isso a essas dicas, obrigado.
21717 Kevin Murrijssen em
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.