Suggerimenti per giocare a golf in Java


86

Esistono scorciatoie utili che possono essere utilizzate in Java?

Come mostrato di seguito, importaggiunge già almeno 17 caratteri a un programma.

import java.io.*;

Capisco che la soluzione semplice sarebbe quella di utilizzare un'altra lingua, ma sembra essere una vera sfida per abbreviare i programmi Java.


I suggerimenti dovrebbero essere specifici di Java: se sono applicabili alla maggior parte dei linguaggi simili a C, appartengono all'elenco più generale di suggerimenti .


9
packagepuò essere saltato.
st0le

In una risposta, non posso semplicemente omettere le importazioni supponendo che siano lì?
Fabricio

1
@Fabricio A meno che OP non lo specifichi.
nyuszika7h,

32
Il miglior consiglio per giocare a golf a Java: non usarlo. ;)
kirbyfan64sos,

4
"Voglio giocare a golf a java" buona fortuna
sagiksp,

Risposte:


85
  • Usa la java più recente possibile. Java 8 ti consente di usare le espressioni lambda, quindi usalo se hai bisogno di qualcosa come gli oggetti funzionali.

  • Definisci funzioni abbreviate per le cose che usi molto. Ad esempio, hai un centinaio di chiamate per exampleClassInstance.doSomething(someParameter), definire una nuova funzione void d(ParameterType p){exampleClassInstance.doSomething(p)}e usarla per salvare alcuni personaggi.

  • Se stai usando un particolare nome di classe lunga più di una volta, ad esempio

    MyEventHandlerProxyQueueExecutorServiceCollectionAccessManagerFactory

    definire invece una nuova classe:

    class X extends MyEventHandlerProxyQueueExecutorServiceCollectionAccessManagerFactory{}

    Se stai utilizzando solo un metodo particolare di quella classe (ma devi comunque istanziarlo), puoi definire contemporaneamente una versione abbreviata all'interno della nuova classe.

  • Utilizzare i parametri del tipo di funzione per abbreviare le cose, ove possibile, in questo modo:

    <T>void p(T o){System.out.println(o);}
  • Usa for(;;)invece di while(true).

  • Non utilizzare modificatori di accesso se non in caso di assoluta necessità.

  • Non usare finalper niente.

  • Non inserire mai un blocco dopo un forciclo (ma un ciclo foreach for(x:y)è diverso). Dichiarazioni aggiuntive dovrebbero essere inserite all'interno fordell'istruzione stessa, come for(int i=0;i<m;a(i),b(++i))c(i);.

  • Usa assegnazione in linea, incremento, istanziazione. Utilizzare le classi in linea anonime, se del caso. Usa lambda invece se possibile. Chiamate di funzione Nest. Alcune funzioni sono garantite per restituire il loro oggetto genitore, queste sono addirittura pensate per essere incatenate insieme.

  • Il tuo mainmetodo throws Exceptionnon li cattura.

  • Errorè più corto di Exception. Se per qualche motivo hai davvero bisogno di throwinviare messaggi nello stack, usa una Error, anche se è una situazione perfettamente normale.

  • Se alcune condizioni richiedono la risoluzione immediata, utilizzare int a=1/0;anziché throw null;o System.exit(0);. In fase di esecuzione, questo genera un ArithmeticException. Se hai già una variabile numerica nel tuo codice, usala invece. (Se hai già import static java.lang.System.*;, vai con exit(0);.)

  • Invece di implementare interfacce, come List<E>, estendere una classe figlio immediata (o non così immediata, se c'è qualche vantaggio nel farlo) classe, come AbstractList<E>, che fornisce implementazioni predefinite della maggior parte dei metodi e richiede solo l'implementazione di alcuni pezzi chiave.

  • Scrivi prima il tuo codice a mano libera, con newline, rientri e nomi di variabili completi. Una volta che hai un codice funzionante, puoi abbreviare i nomi, spostare le dichiarazioni e aggiungere metodi di scelta rapida. Scrivendolo a lungo per iniziare, ti dai più opportunità di semplificare il programma nel suo insieme.

  • Confronta le ottimizzazioni alternative con un pezzo di codice, perché la strategia più ottimale può cambiare radicalmente con piccole modifiche al codice. Per esempio:

    • Se avete solo fino a due chiamate verso Arrays.sort(a), il modo più efficace per è quello di chiamarlo con il suo nome completo, java.util.Arrays.sort(a).
    • Con tre o più chiamate, è più efficiente aggiungere invece un metodo di scelta rapida void s(int[]a){java.util.Arrays.sort(a);}. In questo caso dovrebbe comunque utilizzare il nome completo. (Se hai bisogno di più di un sovraccarico, probabilmente stai sbagliando.)
    • Tuttavia, se il tuo codice deve anche copiare un array ad un certo punto (di solito fatto con un forciclo breve nel golf, in assenza di un metodo di libreria facilmente accessibile), puoi trarre vantaggio dal Arrays.copyOffare il compito. Quando viene utilizzato più di un metodo e vi sono 3 o più chiamate, fare import static java.util.Arrays.*;è il modo più efficiente di fare riferimento a tali metodi. Dopodiché, solo se hai più di 8 chiamate separate sortdovresti utilizzare un metodo di collegamento per esso, e solo per 5 o più chiamate è garantito un collegamento copyOf.

    L'unico modo reale di eseguire tale analisi sul codice è effettivamente eseguire potenziali modifiche sulle copie del codice e quindi confrontare i risultati.

  • Evita di usare il someTypeValue.toString();metodo, invece basta aggiungere someTypeValue+"".

  • Se hai bisogno di Windows, non usare Swing, usa AWT (a meno che tu non abbia davvero bisogno di qualcosa da Swing). Confronta import javax.swing.*;e import java.awt.*;. Inoltre, i componenti in Swing hanno un Jpreposto al loro nome ( JFrame, JLabel, ecc), ma i componenti di AWT non lo fanno ( Frame, Label, ecc)


43

Usa interfaceinvece di class.

In Java 8, i metodi statici sono stati aggiunti alle interfacce. Nelle interfacce, tutti i metodi sono pubblici per impostazione predefinita. conseguentemente

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

ora può essere abbreviato in

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

che è ovviamente più breve.

Ad esempio, ho usato questa funzione in Hello, World! sfida.


8
Non lo sapevo! +1, bel trucco
HyperNeutrino

Sì, meno scaldabagno!
Calcolatrice

3
Devo essere parzialmente in disaccordo (anche, ti ho battuto nella sfida "Hello, World!", Usando quella tecnica).
Olivier Grégoire,

37

Con varargs è possibile " trasmettere " un parametro a un array dello stesso tipo:

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

invece di

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

31

Con un'importazione statica :

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

puoi salvare un po 'di boilerplate in seguito, ma hai bisogno di più invocazioni per raggiungere un payoff:

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

8
: O. Puoi farlo?! E per tutto questo tempo ho pensato che fosse impossibile Java!
Justin il

12
puoi persino usare import static java.lang.System.*.
Johannes Kuhn,

1
So che questa è una vecchia risposta, ma in Java 10 ora puoi fare ciò var o=System.out;che deve essere usato solo due volte prima che ripaghi
Luke Stevens,

@LukeStevens: Beh, forse potresti trovare altri miglioramenti, possibili con Java10, e formare una risposta separata attorno a Java10?
utente sconosciuto il

1
@LukeStevens Funzionerebbe var o=System.out.println?
MilkyWay90

25

L'argomento a mainnon deve essere chiamato argse puoi tagliare alcuni spazi bianchi:

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

andrà bene.


1
Le risposte devono includere la funzione principale se non si afferma esplicitamente di scrivere un programma completo? Ho usato espressioni lambda come risposte.
Makotosan,

3
@Makotosan No, non lo fanno; Le lambda di solito vanno bene.
daniero,

21

Se devi mai usare le espressioni booleane trueo false, sostituiscile con 1>0e 1<0rispettivamente.

Per esempio:

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

Questo esempio di ricerca lineare può essere ridotto a

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

11
Se hai bisogno di molto true/false, basta aggiungere boolean t=1>0,f=1<0;. Quindi, invece di 1>0, utilizzare te salvare due caratteri per uso. Il 1>0metodo di pagamento è di 10 usi.
Geobits

24
@Geobits: boolean t=1>0,f=!t;- un carattere più corto!
Bob

6
L'esempio non è proprio buono. In questo caso e molti altri (!) Puoi evitare di usare true/ falsedirettamente comunque: f|=a[i++]==42;risparmia parecchio.
Ingo Bürk,

@ IngoBürk True. Quando stavo scrivendo questo, pensavo principalmente alle funzioni di libreria che usano boolean, ma dato che al momento della stesura non riuscivo a trovare alcun esempio (di solito non scrivo codice in Java) ho appena scritto un semplice esempio.
ace_HongKongIndipendenza

1
@Geobits non ha molta familiarità con Java ma potresti semplicemente definire 1 e usare t e! T (di nuovo non conosco Java, solo curioso)
Albert Renshaw,

20

Se stai usando un metodo molto, assegna la sua classe residente a una variabile. Ad esempio, assegnare System.outa una variabile:

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

Anche per Integer.parseInt():

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

Questo quasi sicuramente attiverà un avvertimento ide su "accesso al metodo statico da variabile"


((Integer)1).parseInt("1")funziona anche.
Magic Octopus Urn,

5
@carusocomputing new Integer("1")è ancora più breve. Ma ciò che Justin intendeva con la sua risposta è che puoi riutilizzare le variabili che hai già per le chiamate statiche. Come spiego in fondo a questa risposta.
Kevin Cruijssen,

19

Piuttosto che usare la import static java.lang.System.*tecnica per salvare le println()dichiarazioni, ho scoperto che la definizione del seguente metodo è molto più efficace nel salvare i caratteri:

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

Questo perché può essere invocato p(myString)piuttosto out.println(myString)che avere un payoff di carattere molto più rapido e drammatico.


19

Questo può sembrare ovvio, ma ci sono opzioni più brevi per alcune Mathfunzioni:

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 necessario Integer.MAX_VALUE(2147483647), utilizzare -1>>>1. Integer.MIN_VALUE(-2147483648) è meglio scritto 1<<31.


14

Se devi prendere un numero da un argomento (o qualsiasi altra stringa), normalmente vedi qualcosa del tipo:

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

Molte volte, non è necessario un Integer. Molte sfide non usano numeri grandi. Dal momento che Shorte Byteunbox sarà entrambi unboxint , utilizzare il più appropriato valueOf()invece e salvare un paio di byte.

Mantieni la tua variabile effettiva come int, tuttavia, poiché è più corta di entrambe bytee short:

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

Se è necessario eseguire questa operazione per più numeri, è possibile combinare con questo metodo :

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

9
int n=new Byte(a[0]);è tre più corto. Se il numero potrebbe essere maggiore, utilizzare long n=new Long(a[0]), è comunque meglio di ints nella maggior parte dei casi.
Ypnypn,

14

Non usare public class. Il metodo principale deve essere pubblico, ma la sua classe no. Questo codice funziona:

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

Puoi correre java Sanche se class Snon è una classe pubblica. ( Aggiornamento: stavo usando Java 7 quando ho scritto questo suggerimento. In Java 8, il tuo metodo principale dovrebbe essere in un'interfaccia . In Java 5 o 6, il tuo metodo principale dovrebbe essere in un enum .)

Molti programmatori Java non lo sanno! Circa la metà delle risposte a una domanda Stack Overflow su main in una classe non pubblica afferma erroneamente che il metodo principale deve essere in una classe pubblica. Adesso lo sai meglio. Elimina publicin public classe salva 7 caratteri.


1
A meno che non si stia prendendo di mira un Java precedente alla 1.8, il costrutto interface s{static void main(String[]...è più breve. Se è necessario disporre di un file sorgente compilabile e del metodo principale. Perché in un'interfaccia Java 1.8, tutti i metodi sono pubblici in modo da poter saltare il modificatore sui metodi.
Douglas tenuto il

Di recente non ho usato Java, quindi la mia risposta è obsoleta. Ho dimenticato che le interfacce possono avere metodi in Java 8.
kernigh,

Non l'ho imparato dalla programmazione; L'ho imparato dal golf :)
Douglas Held,

14

Alcuni piccoli consigli sul code-golf

Questi suggerimenti erano un po 'troppo piccoli per una risposta separata, quindi userò questa risposta per suggerimenti di codegolfing molto piccoli che ho trovato o trovato, e non sono ancora menzionati negli altri suggerimenti:

Rimozione dell'ultimo carattere di una stringa:

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

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

In alcuni casi sai in anticipo quale è l'ultimo carattere e sai anche che questo personaggio compare una sola volta nella stringa. In tal caso puoi .splitinvece utilizzare :

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

Scorciatoie di codifica:

// 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

Tutte le codifiche hanno un nome canonico utilizzato java.nionell'API, nonché un nome canonico utilizzato nelle API java.ioe java.lang. Ecco un elenco completo di tutte le codifiche supportate in Java. Quindi usa sempre il più corto dei due; il secondo è generalmente più breve (come UTF-8vs utf8, Windows-1252vs Cp1252, ecc.), ma non sempre ( UTF-16BEvs UnicodeBigUnmarked).

Booleano casuale:

// 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:

Esistono molti modi diversi per verificare la presenza di numeri primi o ottenere tutti i numeri primi, ma la risposta di @ SaraJ qui è la più breve. Ecco un copia-incolla come riferimento:

// 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: di solito è possibile unirlo con altri loop esistenti a seconda di come si desidera utilizzarlo, quindi non sarà necessario un metodo separato. Ciò ha consentito di risparmiare molti byte in questa risposta, ad esempio.

Troncamento intero anziché Math.floor / Math.ceil:

Se stai usando doppi / float positivi e li vuoi floor, non usare Math.floorma usa (int)invece un -cast (poiché Java si tronca su numeri interi):

double d = 54.99;

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

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

// Outputs 54 for both

Lo stesso trucco può essere applicato ai doppi / float negativi che vuoi ceilinvece:

double d = -54.99;

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

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

// Outputs -54 for both

Usa &1invece di%2 per sbarazzarsi della parentesi:

Poiché la Precedenza operatore di &è inferiore agli operatori aritmetici predefiniti come */+-e %, in alcuni casi è possibile eliminare la parentesi.

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

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

Nota che questo non aiuta davvero nei controlli booleani, perché poi avresti ancora bisogno di parentesi, sono solo spostati un po ':

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

BigIntegers e creazione di variabili per chiamate a metodi statici:

Quando si utilizza BigIntegers, crearlo solo una volta che è possibile riutilizzare. Come forse sapete, BigInteger contiene campi statici per ZERO, ONEe TEN. Quindi quando usi solo quei tre, non hai bisogno di un importma puoi usarlo java.Math.BigIntegerdirettamente.

// 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                  

NOTA: è necessario utilizzare =nullcosì tè inizializzato per poter usaret. .

A volte puoi aggiungere più BigInteger per crearne un altro per salvare byte. Quindi supponiamo che tu voglia avere i BigIntegers 1,10,12per qualche 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

Come sottolineato correttamente nei commenti, il trucco con le BigInteger t=null;sue chiamate a metodi statici può essere utilizzato anche con altre classi.
Ad esempio, questa risposta del 2011 può essere giocata a golf:

// 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() invece di toCharArray()

Quando vuoi passare in rassegna i caratteri di una stringa, di solito esegui questa operazione:

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

Il ciclo sopra i caratteri può essere utile quando li si stampa o si aggiunge a una stringa o qualcosa di simile.

Tuttavia, se si utilizzano i caratteri solo per alcuni calcoli del numero unicode, è possibile sostituire il charcon int, E è possibile sostituire toCharArray()con getBytes():

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

O ancora più breve in Java 8+:

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

In Java 10+ è ora possibile eseguire il looping del carattere da stampare in 22 byte:

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

Articolo casuale da un 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

Controlla se una stringa contiene spazi iniziali / finali

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

Perché questo funziona, quando !=su Stringhe è necessario verificare il riferimento anziché il valore in Java? Perché String#trimrestituirà " Una copia di questa stringa con lo spazio bianco iniziale e finale rimosso, o questa stringa se non ha spazio bianco iniziale o finale . " L'ho usato, dopo che qualcuno me l'ha suggerito, in questa mia risposta .

Palindrome:

Per verificare se una stringa è un palindromo (tenendo presente sia la lunghezza pari che quella dispari delle stringhe), questa è la più breve ( .containsfunziona qui perché sappiamo che sia la stringa stessa che la sua forma invertita sono di uguale lunghezza):

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

.contains(...)invece di .equals(...+"")ringraziare il commento di @assylias qui .

O è 0 o entrambi sono 0?

Penso che molti lo sappiano già: se vuoi controllare se uno ao bè zero, moltiplica invece per salvare byte:

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

E se vuoi controllare se entrambi ae bsono zero, puoi usare un bit-OR o aggiungerli insieme se sono sempre positivi:

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)

Pari = 1, dispari = -1; o 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

Il motivo per cui aggiungo questo è stato dopo aver visto k+(k%2<1?1:-1)in questa risposta :

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

nTempi di loop nel programma completo

Se abbiamo una sfida in cui un programma completo è obbligatorio e dobbiamo ripetere un determinato numero di volte, possiamo fare quanto segue:

// 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

Lo stesso vale quando dobbiamo prendere questo intervallo come input:

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

Ringraziamo @JackAmmo in questo commento .

try-finally invece di try-catch (Eccezione e) quando ritorna e quando usarlo

Se non puoi usare un throws Exceptionma catchdevi e fare qualcosa con esso prima di tornare, puoi finallyinvece usare :

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

Per quanto riguarda un esempio di quando usare un try-catch, posso fare riferimento a questa mia risposta (il merito del golf indiretto va a @KamilDrakari ). In questa sfida dobbiamo passare in diagonale su una matrice NxM, quindi dobbiamo determinare se la quantità di colonne o la quantità di righe è la più bassa come la massima nel ciclo for (che è piuttosto costoso in termini di byte:) i<Math.min(a.length,a[0].length). Quindi, semplicemente catturare l' ArrayIndexOutOfBoundsExceptionutilizzo catch-finallyè più breve di questo controllo e quindi salva byte:

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: Questo ha funzionato solo a causa di return r;in the finally. Mi è stato suggerito di modificare la prima cella, come ha fatto @KamilDrakari nella sua risposta C # per salvare byte. Tuttavia, in Java questo significa che dovrò cambiarlo in m->{try{for(int i=1;;m[0][0]=f(m[0][0],m[i][i++]));}catch(Exception e){}}(73 byte), aumentando effettivamente il conteggio dei byte invece di diminuire se avessi potuto usare finally.

Math.pow (2, n)

Quando vuoi una potenza di 2, un approccio bit-saggio è molto più breve:

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

Combinazione di controlli logici e bit bit anziché utilizzare la parentesi

Penso che ormai sia ben noto &e che |possa essere usato al posto di &&e ||nei controlli logici Java (booleani). In alcuni casi dovresti comunque utilizzare &&invece di &prevenire errori, ad esempio index >= 0 && array[index].doSomething. Se &&verrà modificato in &qui, valuterà comunque la parte in cui utilizza l'indice nell'array, causando un ArrayIndexOutOfBoundsException, quindi l'utilizzo di &&in questo caso anziché& .

Finora le basi di &&/ ||vs &/| in Java.

Quando si desidera verificare (A or B) and C, il più breve potrebbe sembrare utilizzare gli operatori bit-saggio come questo:

(A|B)&C    // 7 bytes

Tuttavia, poiché gli operatori bit-wise hanno la precedenza dell'operatore sui controlli logici, è possibile combinare entrambi per salvare un byte qui:

A|B&&C     // 6 bytes

Usa n+=...-ninvece di(long)...

Se hai un long sia in sia in output in lambda, ad esempio quando lo usi Math.pow, puoi salvare un byte usando n+=...-ninvece di (long)....
Per esempio:

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

Questo salvato un byte in questa risposta di miniera , e anche due byte combinando -n-1a +~nin questa risposta di mine .


Più in generale per il tuo ultimo punto, puoi accedere / invocare membri statici da un contesto non statico come un'istanza dell'oggetto.
Colpisci il

1
Non capisco il tuo consiglio sul ceil. Perché vorresti soffiare positive integers? Inoltre, non sono sicuro se l'implementazione ceil funziona .
Jonathan Frech,

1
since Java automatically floors on integers; Penso che il termine corretto sia troncamento , non pavimentazione .
Jonathan Frech,

1
Un'altra strategia del PalindromeString t="";for(int i=s.length();--i>=0;t+=s.charAt(i));return s.equals(t);
Roberto Graham,

1
@RobertoGraham In realtà ho copiato il mio codice originale dalla sfida sbagliata .. s.equals(new StringBuffer(s).reverse()+"")È abbastanza.
Kevin Cruijssen,

11

Per il golf che non richiede input, è possibile utilizzare blocchi statici ed eseguirlo bene senza alcun metodo principale, basta compilarlo con Java 6.

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

1
Hai provato a compilare ed eseguirlo? Questo blocco viene eseguito quando la classe viene caricata dal programma di caricamento classi. Ma il programma di caricamento classi non carica nulla fino a quando non conosce una classe con un metodo principale.
Cruncher,

@Cruncher Puoi aggirarlo da solo dicendo javasulla riga di comando / in un file manifest quale classe caricare.
AJMansfield,

6
@Cruncher, funzionava con Java 6. Java 7 ha cambiato il modo in cui funziona.
Peter Taylor,

1
Genera un'eccezione alla fine, ma funziona! Anche in Java 7
stommestack il

2
@JopVernooij Se non vuoi avere un'eccezione lanciata in faccia, puoi system.exit (), ma
perderai

11

Sappiamo tutti del bit per bit xor ( ^), ma è anche un xor logico.

Così (a||b)&&!(a&&b)semplicemente diventa a^b.

Ora possiamo usare xor.

Inoltre , gli operatori |e & anche il lavoro , basta ricordare che la precedenza dell'operatore cambia.


5
Finché ricordi la precedenza, puoi usare & e |anche. Potrebbe essere utile se le tue condizioni sono già tra parentesi o se stai già lavorando con booleani.
Geobits

1
Se hai bisogno di una precedenza (molto) più bassa, puoi usare !=invece ^per xor e ==per xnor
Cyoce

11

Non è necessario usare Character.toLowerCase(char c). Invece usa (c|32). Invece di Character.toUpperCase(char c)usare (c&~32). Funziona solo con lettere ASCII.


c|~32tenderebbe a risultare in -1 ... migliore da usare c-32.
feersum

5
@feersum Non funzionerebbe se si volesse creare una lettera maiuscola.
TheNumberOne il

11

Converti stringa in numero

Esistono diversi modi per convertire una stringa in un valore numerico:

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

Codice ABC :

// 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

nuova ABC :

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

Quindi, per il golf del codice, è meglio usare il costruttore quando si converte una stringa in un valore numerico.

Lo stesso vale per Double; Float; e Byte.


Ciò non si applica sempre quando è possibile riutilizzare una primitiva già presente come oggetto.
Ad esempio, supponiamo di avere il seguente codice:

// 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
}

È possibile utilizzare al .decodeposto del costruttore più corto riutilizzando il parametro come oggetto:

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

Non usare Random!

In generale, se hai bisogno di numeri casuali, Randomè un modo orribile per farlo *. Molto meglio da usare Math.random()invece. Per usare Random, devi fare questo (diciamo che abbiamo bisogno di un int):

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

Confrontalo con:

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);

Il primo metodo accetta 41+15ncaratteri ( nè il numero di chiamate). Il secondo è 25ncaratteri e il terzo è 43+7n.

Quindi, se ne hai bisogno solo una o due volte, usa il Math.random()metodo inline . Per tre o più chiamate, risparmierai utilizzando una funzione. O si salva caratteri sul primo utilizzo sopra Random.


Se stai già utilizzando Math.random()per double, ricorda che in quattro utilizzi, è ancora un risparmio per tirarlo fuori in:

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

Per 33 caratteri, risparmierai 10 su ogni chiamata a r()


Aggiornare

Se hai bisogno di un numero intero e vuoi risparmiare sul cast, non farlo! Java si avvia automaticamente se si esegue un'operazione anziché un'assegnazione. Confrontare:

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

* A meno che non sia necessario eseguire il seeding del PRNG per risultati prevedibili. Quindi, non vedo molto da fare.


2
Non dimenticare Random#nextGaussianperò.
Giustino,

@Quincunx Vero, fare i calcoli per ottenere una buona distribuzione normale ti farebbe perdere tutti i risparmi ottenuti. Mi riferirò a ciò come l'eccezione che dimostra la regola;)
Geobits,

Si noti che (int)(Math.random()*9)ha una distorsione del modulo molto piccola, poiché Math.random()restituisce 2 53 valori possibili e 2 53 non è un multiplo di 9. La probabilità di ciascun numero è compresa tra 1/9 più o meno 5 / (9 * 2 ** 53), un errore così piccolo, è quasi esattamente 1/9.
kernigh,

@kernigh Bene, stavo usando 9solo un esempio, potrebbe essere qualsiasi cosa. Sono relativamente sicuro che nextInt()(o qualsiasi altro Randommetodo) abbia anche un piccolo pregiudizio, proprio a causa del funzionamento del PRNG di Java.
Geobits,

1
Qualcosa di correlato a quando vuoi un booleano casuale: invece di new java.util.Random().nextBoolean()te puoi usare Math.random()<.5.
Kevin Cruijssen,

7

Non so se considereresti questo Java "puro", ma l' elaborazione ti consente di creare programmi con poca configurazione iniziale (completata automaticamente).

Per l'output della console, puoi avere qualcosa di semplice come:

println("hi"); //done

per l'output grafico, un po 'di più:

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 Ottima risorsa! Sarò sicuro di giocarci.
Rob,

Andrebbe bene se aggiungessi le risposte degli altri a questo? O questo sconfigge lo scopo di un wiki della comunità?
Rob,

2
A proposito, non devi nemmeno chiamare sizeaffatto; verrà impostato automaticamente su un quadrato di 100 per 100 pixel. Nella maggior parte dei sistemi operativi, la cornice circostante sarà circa il doppio di quella, con il quadrato centrato e il resto dell'area riempito con il contenuto prelevato dal desktop.
AJMansfield,

1
Per l'output grafico, se non hai bisogno di animazioni, puoi semplicemente scrivere tutto al di fuori setup()e draw()utilizzare la "modalità statica". Puoi anche usare colori esadecimali a 6 cifre e l'interprete li cambierà, il che a volte paga ( #FF8000< 255,128,0), e se stai usando la scala di grigi devi specificare solo un numero ( 255< 255,255,255)
quat

7

Accorciamento di ritorno

È possibile abbreviare le dichiarazioni di restituzione di stringhe di un byte con:

return "something";

per

return"something";

E, se ti capita di iniziare la tua dichiarazione di ritorno con una parentesi, puoi fare la stessa cosa con loro:

return (1+taxRate)*value;

per

return(1+taxRate)*value;

Immagino che le citazioni siano considerate tra parentesi? In realtà l'ho raccolto tramite AppleScript, abbastanza stranamente, e ho pensato che valesse la pena menzionarlo.


1
Lo stesso vale per i segni numerici, come al return-n;posto di return -n;o return~n;anziché return ~n;. Oltre alle virgolette singole anziché doppie:return'A';
Kevin Cruijssen,

1
Fondamentalmente, funziona per tutto ciò che non può far parte di un identificatore (cioè non lettera e non cifra).
Paŭlo Ebermann,

7

Non abbiate paura di usare la notazione scientifica

Se hai a che fare con doppi o float, puoi usare la notazione scientifica per i numeri. Quindi, invece di scrivere double a=1000, puoi cambiarlo in double a=1e3per salvare 1 byte.


7

Prova a usare intinvece diboolean

In alcuni casi ho scoperto che è più breve restituire un valore intero da un metodo che normalmente restituirebbe un valore booleano, analogamente a quanto si potrebbe fare nei programmi C.

Subito dopo la mazza intè 4 byte più corta di boolean. Ogni volta che scrivi return 0invece di return 1<0salvare altri 2 byte e lo stesso per return 1 over return 1>0.

Il problema qui è che ogni volta che si desidera utilizzare direttamente il valore restituito come valore booleano, il costo è di 2 byte ( if(p(n))v. if(p(n)>0)). Questo può essere compensato dall'uso dell'aritmetica booleana. Dato uno scenario inventato in cui si desidera scrivere

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

puoi invece scrivere

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

per salvare 2 byte.


6
Lo faccio abbastanza spesso durante il golf, ma tieni presente che il consenso generale è quello 0e 1non costituisce falso / vero in Java (e JLS non li considera neanche in questo modo). Quindi, se il golf richiede specificamente verità / falsità, è necessario booleandolo (e, sfortunatamente, renderlo una booleanfunzione, lanciando ancora più byte).
Geobits il

2
t[0]+=p(n):10?0;È valido anche questo?
dorukayhan

@dorukayhan no, dovrebbe esserlo t[0]+=p(n)?10:0; . (L'ho modificato.)
Paŭlo Ebermann,

6

Se usi enum invece di classe , salvi un personaggio.

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

    }
}

Ma devi introdurre almeno un'istanza enum (F, G, H in questo esempio) che devono ripagarsi.


2
Sembra che non ti occorrono istanze enum. L'ho fatto enum M{;public static void main(String[]a){...}senza problemi.
Danny,

3
@Danny Ma poi non salva alcun personaggio. class M{è esattamente della stessa lunghezza di enum M{;. In tal caso, andrei con il classperché è più bello (IMO)
Justin

1
almeno per me ha enum{lavorato senza un ;dopo; è solo l'IDE gemendo che c'è un errore ma il compilatore lo accetta
masterX244

@ masterX244 Quale compilatore / versione? Il mio genera uno scatto d'ira e non lo farà.
Geobits

ha funzionato su java 1.7 per me (è apparso necessario indagare sull'ulteriore causa con un aggiornamento a .8 ha smesso di funzionare)
masterX244

5

Quando hai un metodo che dovrebbe restituire un booleano Boolean, cioè:

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

È possibile modificare il tipo boolean/ Booleanreturn in Objectper salvare 1 byte:

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

Inoltre, come avrai notato, puoi usare un <1segno di spunta invece di==0 salvare un byte. Anche se questo è più un suggerimento generale per il codice-golf invece che specifico per Java.
Questo è usato principalmente quando l'intero non può essere negativo, come verificare la lunghezza:

a.length<1

invece di

a.length==0

1
Bel consiglio! Potresti voler aggiungere un altro esempio nella sezione "se non può essere negativo" per illustrarlo, poiché c(-21)ritorna truecon quello corrente.
Geobits,

Chiarito. Inoltre, non intendi c(-20)invece di -21? -21 % 5 = 4e -20 % 5 = 0.
Kevin Cruijssen,

1
No, intendevo -21. -21 % 5 != 4in Java, che è il mio punto. Il divisibile per cinque funzione potrebbe funzionare correttamente se il modulo restituito sempre non negativo, ma non è così. Vedi questo frammento di esempio .
Geobits,

@Geobits Ah, grazie per l'esempio. Non uso quasi mai numeri negativi %, quindi ho dimenticato che Java restituisce il resto invece del modulo, quindi la differenza.
Kevin Cruijssen,

5

Come disegnare in Java ...

Ecco la piastra della caldaia della vernice GUI più corta possibile:

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

Giocato a golf per 111 byte:

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

5

Evitare StringBuilders

L'aggiunta di roba a Stringoccupa molto meno byte.

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

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

Se devi invertire una stringa e stamparla subito, usa 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 devi invertire una stringa e fare qualcosa di diverso dalla stampa, usa un forciclo per volta.

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

3
Un ciclo foreach è più corto di quello StringBufferper l'inversione di stringhe. String b="";for(char c:"Hello, World!".toCharArray()){b=c+b;}
Colpisci il

1
Dovresti anche rimuovere il {}da quel ciclo foreach se intendi usare quel metodo.
Geobits,

1
Salva 2 byte usando String s:"".split("")invece di char c:"".toCharArray().
charlie,

Se hai java.util.stream.Streamgià importato e se hai bisogno di concatenare un'altra chiamata al risultato (come B.chartAt(42)) o se devi solo passare il risultato a una funzione (come f(B)), allora usare for(:)equall è Stream.of("Hello, World!".split("")).reduce("",(a,b)->b+a).
Charlie

Entrambe le righe nel tuo esempio con il for-each possono essere giocate a golf. Il primo può diventare: String b=new StringBuffer("Hello, World!").reverse()+"";( .toStringsostituito con +""), e la seconda linea può diventare: String B="";for(String c:"Hello, World!".split(""))B=c+B;( charda Stringe .toCharArray()a .split("")).
Kevin Cruijssen,

5

Usa Java 10 var

Se si definisce una singola variabile di un tipo specifico, utilizzare var.

Esempi

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

Non utilizzabile in nessuno dei seguenti esempi

var non può essere usato in molti esempi

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 perché questo non funziona con i riferimenti ai metodi, nota che esistono interfacce funzionali standard solo per un piccolo set di firme (e che i metodi possono generare eccezioni verificate).
Jakob,


4

Nella maggior parte dei casi, il programma sarà a thread singolo, ovvero avrà un solo thread in esecuzione. Puoi sfruttare questo fatto utilizzando returnil metodo principale quando devi uscire immediatamente.

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

Confrontalo con "correttamente" terminando il programma:

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

O che punta a null:

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

O dividendo per 0:

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

4

A volte, una singola istruzione for-loop potrebbe essere sostituibile. Considera il seguente codice:

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

Questo è un semplice for-loop che è una soluzione a questa domanda .

Poiché sappiamo che inon sarà abbastanza grande da causare errori StackOverflow, possiamo invece sostituire il for-loop con la ricorsione:

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

Possiamo simulare un loop usando un operatore ternario nell'istruzione return per causare la ricorsione.

Questa riduzione è piuttosto specifica, ma posso immaginare più situazioni in cui ciò potrebbe tornare utile.


4

utilizzando ... (varag) come parametro

In alcuni casi è più breve usare un varargs Java come parametro invece di quelli sciolti.
Per esempio:

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

Sarebbe golfato da molti a questo:

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

Ma si può giocare a golf un byte aggiuntivo a questo:

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

Si noti che tutti e tre i numeri interi sono accessibili solo una volta nel metodo stesso. Poiché intè piuttosto breve, è utile solo se li usi ciascuno solo una volta all'interno del metodo e ne hai tre o più come parametro.

Con parametri più lunghi questo è generalmente più utile però. Ad esempio, questa era la mia risposta originale per questa sfida (calcolare le occorrenze del carattere di input nella stringa di input):

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

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

E mi è stato consigliato di giocare a questo:

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

Ma ho finito per giocare a questo usando ...:

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

NOTA: se la domanda / sfida richiede un input flessibile, è ...possibile accorciarlo []ovviamente. Se la domanda / sfida richiede specificamente, diciamo, tre Stringinput e non Stringconsente un array contenente tre valori, è possibile utilizzare String...invece di String a,String b,String c.


2
Non puoi usare un String[]invece di usare varargs? (salva un altro byte)
Kritixi Lithos

@KritixiLithos Hmm .. buon punto. Ma ciò dipende principalmente dalla flessibilità dell'input per la sfida. Se è consentito un formato di input, questo sarebbe effettivamente più breve. Aggiungerò questo a questi suggerimenti, grazie.
Kevin Cruijssen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.