Consejos para jugar golf en Java


86

¿Hay atajos útiles que se puedan usar en Java?

Como se muestra a continuación, importya agrega al menos 17 caracteres a un programa.

import java.io.*;

Entiendo que la solución simple sería usar otro lenguaje, pero parece ser un verdadero desafío acortar los programas Java.


Las sugerencias deben ser específicas para Java: si son aplicables a la mayoría de los lenguajes tipo C, pertenecen a la lista más general de sugerencias .


99
packageSe puede omitir.
st0le

En una respuesta, ¿no puedo omitir las importaciones suponiendo que estén allí?
Fabricio

1
@Fabricio No, a menos que el OP lo especifique.
nyuszika7h

32
El mejor consejo sobre jugar al golf en Java: no lo uses. ;)
kirbyfan64sos

44
"Quiero jugar golf en Java" buena suerte
sagiksp

Respuestas:


85
  • Usa el Java más reciente posible. Java 8 le permite utilizar las expresiones lambda, así que úsalo si necesitas cualquier cosa, incluso como objetos funcionales.

  • Defina funciones abreviadas para las cosas que usa mucho. Por ejemplo, tiene cientos de llamadas exampleClassInstance.doSomething(someParameter), defina una nueva función void d(ParameterType p){exampleClassInstance.doSomething(p)}y úsela para ahorrarse algunos caracteres.

  • Si está usando un nombre de clase larga particular más de una vez, como

    MyEventHandlerProxyQueueExecutorServiceCollectionAccessManagerFactory

    en su lugar, defina una nueva clase:

    class X extends MyEventHandlerProxyQueueExecutorServiceCollectionAccessManagerFactory{}

    Si solo está utilizando un método particular de esa clase (pero aún necesita crear una instancia), puede definir una versión abreviada dentro de la nueva clase al mismo tiempo.

  • Use parámetros de tipo de función para acortar cosas, donde sea posible, de esta manera:

    <T>void p(T o){System.out.println(o);}
  • Usar en for(;;)lugar de while(true).

  • No use modificadores de acceso a menos que sea absolutamente necesario.

  • No utilizar finalpara nada.

  • Nunca ponga un bloque después de un forbucle (pero un bucle foreach for(x:y)es diferente). Las declaraciones adicionales deben colocarse dentro de la fordeclaración misma, como for(int i=0;i<m;a(i),b(++i))c(i);.

  • Use asignación en línea, incremento, instanciación. Utilice clases en línea anónimas cuando corresponda. Use lambdas en su lugar si es posible. La función de nido llama. Algunas funciones están garantizados para volver a su objeto principal, estos son en realidad incluso significaba que estar encadenado juntos.

  • Su mainmétodo throws Exceptions, no los atrapa.

  • Errores más corto que Exception. Si por alguna razón realmente necesita throwenviar mensajes a la pila, use una Error, incluso si es una situación perfectamente normal.

  • Si alguna condición requiere la terminación inmediata, use en int a=1/0;lugar de throw null;o System.exit(0);. En tiempo de ejecución, esto arroja un ArithmeticException. Si ya tiene una variable numérica en su código, úsela en su lugar. (Si ya lo has hecho import static java.lang.System.*;, ve con exit(0);).

  • En lugar de implementar interfaces, como List<E>, extienda una clase secundaria inmediata (o no tan inmediata, si es que tiene alguna ventaja hacerlo) AbstractList<E>, que proporciona implementaciones predeterminadas de la mayoría de los métodos y requiere solo la implementación de Algunas piezas clave.

  • Escriba su código en letra larga primero, con líneas nuevas, sangría y nombres completos de variables. Una vez que tenga el código de trabajo, puede acortar los nombres, mover las declaraciones y agregar métodos de acceso directo. Al escribirlo mucho para comenzar, tiene más oportunidades de simplificar el programa en su conjunto.

  • Compare optimizaciones alternativas con un fragmento de código, porque la estrategia más óptima puede cambiar drásticamente con cambios muy pequeños en el código. Por ejemplo:

    • Si sólo tiene un máximo de dos llamadas a Arrays.sort(a), la forma más eficiente para es llamarlo con su nombre completo, java.util.Arrays.sort(a).
    • Con tres o más llamadas, es más eficiente agregar un método de acceso directo void s(int[]a){java.util.Arrays.sort(a);}. Esto aún debería usar el nombre completo en este caso. (Si necesita más de una sobrecarga, probablemente lo esté haciendo mal).
    • Sin embargo, si su código necesita copiar también una matriz en algún momento (generalmente hecho con un forciclo corto en el golf, en ausencia de un método de biblioteca de fácil acceso), puede aprovechar Arrays.copyOfpara hacer la tarea. Cuando se usa más de un método, y hay 3 o más llamadas, hacer import static java.util.Arrays.*;es la forma más eficiente de referirse a esos métodos. Después de eso, solo si tiene más de 8 llamadas separadas, sortdebería estar utilizando un método de acceso directo, y solo en 5 o más llamadas está garantizado un acceso directo copyOf.

    La única forma real de realizar dicho análisis en el código es realizar modificaciones potenciales en las copias del código y luego comparar los resultados.

  • Evite usar el someTypeValue.toString();método, solo agregue someTypeValue+"".

  • Si necesita ventanas, no use Swing, use AWT (a menos que realmente necesite algo de Swing). Compara import javax.swing.*;y import java.awt.*;. Además, los componentes de oscilación tienen un Jantepone a su nombre ( JFrame, JLabel, etc.), pero los componentes de AWT no ( Frame, Label, etc.)


43

Usar en interfacelugar de class.

En java 8, se agregaron métodos estáticos a las interfaces. En las interfaces, todos los métodos son públicos por defecto. Por consiguiente

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

ahora se puede acortar a

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

que obviamente es más corto.

Por ejemplo, usé esta función en Hello, World! desafío.


8
Yo no lo sabia! +1, buen truco
HyperNeutrino

¡Yay, menos repetitivo!
CalculatorFeline

3
Tengo que estar parcialmente en desacuerdo (también, te gané en el desafío "¡Hola, Mundo!", Usando esa técnica).
Olivier Grégoire

37

Con varargs puedes "lanzar" un parámetro a una matriz del mismo tipo:

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

en lugar de

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

31

Con una importación estática :

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

puede guardar algo más tarde, pero necesita múltiples invocaciones para obtener un resultado:

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

8
: O. ¡¿Puedes hacerlo?! ¡Y todo este tiempo pensé que esto era imposible Java!
Justin

12
incluso puedes usar import static java.lang.System.*.
Johannes Kuhn

1
Sé que esta es una respuesta anterior, pero en Java 10 ahora puede hacer lo var o=System.out;que solo debe usarse dos veces antes de que valga la pena
Luke Stevens

@LukeStevens: Bueno, ¿tal vez encuentres otras mejoras posibles con Java10 y formes una respuesta separada sobre Java10?
usuario desconocido el

1
@LukeStevens ¿Funcionaría var o=System.out.println?
MilkyWay90

25

mainNo es necesario llamar al argumento to args, y puede cortar algunos espacios en blanco:

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

hará bien.


1
¿Las respuestas deben incluir la función principal si no indica explícitamente escribir un programa completo? He estado usando expresiones lambda como respuestas.
Makotosan

3
@Makotosan No, no lo hacen; Las lambdas suelen estar bien.
daniero

21

Si alguna vez tiene que usar las expresiones booleanas trueo false, reemplácelas con 1>0y 1<0respectivamente.

Por ejemplo:

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

Este ejemplo de búsqueda lineal se puede reducir a

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

11
Si va a necesitar mucho true/false, solo agregue boolean t=1>0,f=1<0;. Luego, en lugar de 1>0usar ty guardar dos caracteres por uso. El pago sobre el 1>0método tiene 10 usos.
Geobits

24
@Geobits: boolean t=1>0,f=!t;- ¡un personaje más corto!
bobbel

66
El ejemplo no es realmente bueno. En este caso y en muchos (!) Otros, puede evitar usar true/ falsedirectamente de todos modos: f|=a[i++]==42;ahorra bastante.
Ingo Bürk

@ IngoBürk True. Cuando escribía esto, pensaba principalmente en las funciones de biblioteca que usa boolean, pero como no pude encontrar ningún ejemplo al momento de escribir (generalmente no codifico en Java), simplemente escribí un ejemplo simple.
ace_HongKongIndependence

1
@Geobits no está demasiado familiarizado con Java, pero ¿podría definir 1 y usar t y! T (de nuevo, no sé Java, solo curiosidad)
Albert Renshaw

20

Si va a utilizar mucho algún método, asigne su clase residente a una variable. Por ejemplo, asignar System.outa una variable:

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

También para Integer.parseInt():

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

Esto seguramente desencadenará una advertencia ide sobre "acceder al método estático desde la variable"


((Integer)1).parseInt("1")también funciona
Urna de pulpo mágico

55
@carusocomputing new Integer("1")es aún más corto. Pero lo que Justin quiso decir con su respuesta es que puede reutilizar variables que ya tiene para llamadas estáticas. Como explico al final de esta respuesta.
Kevin Cruijssen

19

En lugar de usar la import static java.lang.System.*técnica para ahorrar en las println()declaraciones, descubrí que definir el siguiente método es mucho más efectivo para guardar caracteres:

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

Esto se debe a que se puede invocar en p(myString)lugar de out.println(myString)tener una recompensa de personaje mucho más rápida y dramática.


19

Esto puede parecer obvio, pero hay opciones más cortas para algunas Mathfunciones:

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

Si lo necesita Integer.MAX_VALUE(2147483647), use -1>>>1. Integer.MIN_VALUE(-2147483648) está mejor escrito 1<<31.


14

Si necesita obtener un número de un argumento (o cualquier otra cadena), normalmente verá algo como:

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

Muchas veces, no necesitas un Integer. Muchos desafíos no usan grandes cantidades. Dado Shorty Byteserá tanto unbox a una int, utilizar el más adecuado valueOf()en su lugar y guardar un par de bytes.

Sin embargo, mantenga su variable real como una int, ya que es más corta que ambas bytey short:

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

Si necesita hacer esto para varios números, puede combinarlo con este método :

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

99
int n=new Byte(a[0]);Es tres más corto. Si el número puede ser mayor, use long n=new Long(a[0]), aún es mejor que ints en la mayoría de los casos.
Ypnypn

14

No utilice public class. El método principal debe ser público, pero su clase no. Este código funciona:

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

Puedes correr java Saunque class Sno sea una clase pública. ( Actualización: estaba usando Java 7 cuando escribí este consejo. En Java 8, su método principal debería estar en una interfaz . En Java 5 o 6, su método principal debería estar en una enumeración ).

¡Muchos programadores de Java no lo saben! Aproximadamente la mitad de las respuestas a una pregunta de Stack Overflow sobre main en una clase no pública afirman erróneamente que el método main debe estar en una clase pública. Ahora lo sabes mejor. Eliminar el publicen public classy guardar 7 caracteres.


1
A menos que esté apuntando a un Java anterior a 1.8, la construcción interface s{static void main(String[]...es más corta. Si debe tener un archivo fuente compilable y un método principal. Porque en una interfaz Java 1.8, todos los métodos son públicos, por lo que puede omitir el modificador en los métodos.
Douglas celebrada el

No he usado Java recientemente, por lo que mi respuesta está desactualizada. Olvidé que las interfaces pueden tener métodos en Java 8.
kernigh

No lo aprendí de la programación; Lo aprendí del golf :)
Douglas Held

14

Algunos pequeños consejos de golf de código

Estos consejos eran demasiado pequeños para respuestas separadas, por lo que utilizaré esta respuesta para consejos muy pequeños de codegolf que encontré o se me ocurrieron, y que aún no se mencionan en los otros consejos:

Eliminar el último carácter de una cadena:

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

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

En algunos casos, usted sabe de antemano cuál es el último carácter, y también sabe que este carácter solo aparece una vez en la Cadena. En ese caso, puede usar .spliten su lugar:

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

Atajos de codificación:

// 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 las codificaciones tienen un nombre canónico utilizado en la java.nioAPI, así como un nombre canónico utilizado en los java.ioy java.langlas API. Aquí hay una lista completa de todas las codificaciones compatibles en Java. Así que siempre usa el más corto de los dos; el segundo suele ser más corto (como UTF-8vs utf8, Windows-1252vs Cp1252, etc.), pero no siempre ( UTF-16BEvs UnicodeBigUnmarked).

Booleano aleatorio:

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

Hay muchas formas diferentes de verificar los números primos u obtener todos los números primos, pero la respuesta de @ SaraJ aquí es la más corta. Aquí hay una copia-pegar como referencia:

// 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: Por lo general, puede fusionarlo con otros bucles existentes dependiendo de cómo desee usarlo, por lo que no necesitará un método separado. Esto ahorró muchos bytes en esta respuesta, por ejemplo.

Truncamiento de enteros en lugar de Math.floor / Math.ceil:

Si está utilizando dobles / flotantes positivos y desea floorutilizarlos, no los utilice, Math.floorsino que use un (int)-cast en su lugar (ya que Java se trunca en los enteros):

double d = 54.99;

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

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

// Outputs 54 for both

El mismo truco se puede aplicar a dobles / flotantes negativos que desee ceil:

double d = -54.99;

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

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

// Outputs -54 for both

Use en &1lugar de %2deshacerse del paréntesis:

Debido a que la precedencia de operadores de &es menor que los operadores aritméticos predeterminados como */+-y %, en algunos casos puede deshacerse del paréntesis.

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

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

Tenga en cuenta que esto realmente no ayuda en las comprobaciones booleanas, porque aún necesitaría paréntesis, solo se movieron un poco:

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

BigIntegers y creando variables para llamadas a métodos estáticos:

Cuando use BigIntegers, créelo solo una vez y luego podrá reutilizarlo. Como ya sabrán, BigInteger contiene campos estáticos para ZERO, ONEy TEN. Entonces, cuando solo usa esos tres, no necesita un importpero puede usarlo java.Math.BigIntegerdirectamente.

// 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: Usted tiene que usar =nullpor lo que tse inicializa con el fin de utilizar t..

A veces puede agregar múltiples BigIntegers para crear otro para guardar bytes. Entonces, digamos que quieres tener BigIntegers 1,10,12por alguna razón:

// 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 se señaló correctamente en los comentarios, el truco con BigInteger t=null;sus llamadas a métodos estáticos también se puede usar con otras clases.
Por ejemplo, esta respuesta de 2011 se puede jugar:

// 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() en lugar de toCharArray()

Cuando desee recorrer los caracteres de una Cadena, generalmente hará esto:

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

Recorrer los caracteres puede ser útil al imprimirlos, agregarlos a una cadena o algo similar.

Sin embargo, si solo usa los caracteres para algunos cálculos de números Unicode, puede reemplazarlos charcon intY, y puede reemplazar toCharArray()con getBytes():

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

O incluso más corto en Java 8+:

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

En Java 10+, el bucle sobre el carácter a imprimir ahora también se puede hacer en 22 bytes:

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

Artículo aleatorio 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

Compruebe si una cadena contiene espacios iniciales / finales

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 qué funciona esto, cuando !=en Strings se busca una referencia en lugar de un valor en Java? Porque String#trimdevolverá " Una copia de esta cadena con espacios en blanco iniciales y finales eliminados, o esta cadena si no tiene espacios en blanco iniciales o finales " . Utilicé esto, después de que alguien me sugirió esto, en esta respuesta mía .

Palíndromo:

Para verificar si una Cadena es un palíndromo (teniendo en cuenta las longitudes pares e impares de las Cadenas), esta es la más corta ( .containsfunciona aquí porque sabemos que tanto la Cadena en sí como su forma invertida tienen la misma longitud):

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

.contains(...)en lugar de .equals(...+"")gracias al comentario de @assylias aquí .

¿O es 0 o ambos son 0?

Creo que la mayoría ya conoce esta: si desea comprobar si ao bes cero, multiplique en su lugar para guardar bytes:

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

Y si desea verificar si ambos ay bson cero, puede usar un OR bit a bit o agregarlos juntos si siempre son 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, impar = -1; o viceversa

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

La razón por la que agrego esto fue después de ver k+(k%2<1?1:-1)en esta respuesta :

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

nTiempos de bucle en el programa completo

Si tenemos un desafío en el que un programa completo es obligatorio, y necesitamos realizar un ciclo específico de veces, podemos hacer lo siguiente:

// 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 mismo se aplica cuando tenemos que tomar este rango 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

Gracias a @JackAmmo en este comentario .

try-finally en lugar de try-catch (Excepción e) al regresar y cuándo usarlo

Si no puede usar un throws Exceptionpero tiene que catchhacerlo y hacer algo con él antes de regresar, puede usar finallyen su lugar:

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

En cuanto a un ejemplo de cuándo usar un try-catch, puedo referirme a esta respuesta mía (el crédito por el golf indirecto va a @KamilDrakari ). En este desafío, debemos realizar un bucle en diagonal sobre una matriz NxM, por lo que debemos determinar si la cantidad de columnas o la cantidad de filas es la más baja como nuestro máximo en el bucle for (que es bastante costoso en términos de bytes i<Math.min(a.length,a[0].length)). Por lo tanto, simplemente capturar el ArrayIndexOutOfBoundsExceptionuso catch-finallyes más corto que esta verificación y, por lo tanto, ahorra 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: Esto solo funcionó debido return r;al final. Me han sugerido que modifique la primera celda, como @KamilDrakari hizo en su respuesta de C # para guardar bytes. Sin embargo, en Java esto significa que tendré que cambiarlo a m->{try{for(int i=1;;m[0][0]=f(m[0][0],m[i][i++]));}catch(Exception e){}}(73 bytes), en realidad aumentando el recuento de bytes en lugar de disminuir si pudiera haberlo usado finally.

Math.pow (2, n)

Cuando quieres una potencia de 2, un enfoque basado en bits es mucho más corto:

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

Combinando controles lógicos y de bits en lugar de usar paréntesis

Creo que ahora es bien conocido eso &y |puede usarse en lugar de &&y ||en las comprobaciones lógicas Java (booleanas). Sin embargo, en algunos casos aún querrás usar en &&lugar de &evitar errores, como index >= 0 && array[index].doSomething. Si &&se cambiara a &aquí, todavía evaluará la parte donde usa el índice en la matriz, causando un ArrayIndexOutOfBoundsException, de ahí el uso de &&en este caso en lugar de &.

Hasta ahora, los conceptos básicos de &&/ ||vs &/ |en Java.

Cuando desee verificar (A or B) and C, el más corto puede parecer usar los operadores de bits como este:

(A|B)&C    // 7 bytes

Sin embargo, debido a que los operadores de bits tienen prioridad de operador sobre las comprobaciones lógicas, puede combinar ambos para guardar un byte aquí:

A|B&&C     // 6 bytes

Usar en n+=...-nlugar de(long)...

Cuando tiene un largo como entrada y salida en un lambda, por ejemplo, cuando lo usa Math.pow, puede guardar un byte usando en n+=...-nlugar de (long)....
Por ejemplo:

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

Esto ahorró un byte en esta respuesta mía , e incluso dos bytes mediante la combinación de -n-1a +~nen esta respuesta mía .


De manera más general para su último punto, puede acceder / invocar miembros estáticos desde un contexto no estático, como una instancia del objeto.
Poke

1
No entiendo tu punta de techo. ¿Por qué querrías un techo positive integers? Además, no estoy seguro de si la implementación del techo funciona .
Jonathan Frech

1
since Java automatically floors on integers; Creo que el término apropiado es truncamiento , no piso .
Jonathan Frech

1
Otra estrategia de PalindromeString t="";for(int i=s.length();--i>=0;t+=s.charAt(i));return s.equals(t);
Roberto Graham el

1
@RobertoGraham Realmente copié mi código original del desafío incorrecto ... Simplemente s.equals(new StringBuffer(s).reverse()+"")es suficiente.
Kevin Cruijssen

11

Para jugar al golf que no requiere entrada, puede usar bloques estáticos y ejecutarlo bien sin ningún método principal, solo compílelo con Java 6.

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

1
¿Intentaste compilarlo y ejecutarlo? Este bloque se ejecuta cuando el cargador de clases carga la clase. Pero el cargador de clases no cargará nada hasta que sepa de una clase con un método principal.
Cruncher

@Cruncher Puede solucionarlo usted mismo diciendo javaen la línea de comando / en un archivo de manifiesto qué clase cargar.
AJMansfield

66
@Cruncher, esto funcionó con Java 6. Java 7 cambió la forma en que funciona.
Peter Taylor

1
¡Lanza una excepción al final pero funciona! Incluso en Java 7
stommestack

2
@JopVernooij Si no quieres que te arrojen una excepción, puedes system.exit (), pero desperdiciarás personajes, ningún desafío de golf te
pedirá

11

Todos conocemos el bit xor ( ^), pero también es un xor lógico.

Entonces (a||b)&&!(a&&b)simplemente se convierte a^b.

Ahora podemos usar xor.

Además , los operadores |y & también funcionan , solo recuerde que los cambios de precedencia de operadores.


55
Mientras recuerde la precedencia, puede usar & y |también. Puede ser útil si sus condiciones ya están entre paréntesis, o si ya está trabajando con booleanos.
Geobits

1
Si necesita una (mucha) precedencia más baja, puede usarla en !=lugar de ^para xor y ==para xnor
Cyoce

11

No tienes que usar Character.toLowerCase(char c). En lugar de usar (c|32). En lugar de Character.toUpperCase(char c)usar (c&~32). Esto solo funciona con letras ASCII.


c|~32tendería a resultar en -1 ... mejor para usar c-32.
feersum

55
@feersum Eso no funcionaría si quisieras hacer una letra mayúscula mayúscula.
TheNumberOne

11

Convertir cadena en número

Hay varias formas de convertir una cadena en un 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

nuevo ABC :

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

Por lo tanto, para golf de código, es mejor usar el constructor al convertir una cadena en un valor numérico.

Lo mismo se aplica a Double; Float; y Byte.


Esto no siempre se aplica cuando puede reutilizar una primitiva ya presente como objeto.
Como ejemplo, digamos que tenemos el siguiente 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
}

Puede usar en .decodelugar del constructor más corto reutilizando el 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

¡No lo uses Random!

En general, si necesita números aleatorios, Randomes una forma horrible de hacerlo *. Mucho mejor usar Math.random()en su lugar. Para usar Random, debes hacer esto (digamos que necesitamos un int):

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

Compare eso con:

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

y:

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

El primer método toma 41+15ncaracteres ( nes el número de llamadas). El segundo son los 25npersonajes, y el tercero es 43+7n.

Entonces, si solo lo necesita una o dos veces, use el Math.random()método en línea . Para tres o más llamadas, ahorrará utilizando una función. Cualquiera de los dos personajes ahorra en el primer uso más Random.


Si ya está usando Math.random()para double, recuerde que con cuatro usos, todavía es un ahorro sacarlo en:

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

Para 33 caracteres, ahorrará 10 en cada llamada a r()


Actualizar

Si necesita un número entero y desea ahorrar en la conversión, ¡no lo eche! Java se convierte automáticamente si realiza una operación en lugar de una asignación. Comparar:

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

* A menos que tenga que sembrar el PRNG para obtener resultados predecibles. Entonces, no veo mucha forma de evitarlo.


2
Sin Random#nextGaussianembargo, no te olvides .
Justin

@Quincunx Cierto, hacer los cálculos para obtener una buena distribución normal te haría perder los ahorros que obtuviste. Me referiré a eso como la excepción que prueba la regla;)
Geobits

Tenga en cuenta que (int)(Math.random()*9)tiene un sesgo de módulo muy pequeño, porque Math.random()devuelve 2 53 valores posibles, y 2 53 no es un múltiplo de 9. La probabilidad de cada número está dentro de 1/9 más o menos 5 / (9 * 2 ** 53), Un error tan pequeño que es casi exactamente 1/9.
kernigh

@kernigh Correcto, estaba usando 9solo como ejemplo, podría ser cualquier cosa. Estoy relativamente seguro de que nextInt()(o cualquier otro Randommétodo) también tiene un pequeño sesgo, solo debido a cómo funciona el PRNG de Java.
Geobits

1
Algo relacionado para cuando quieres un booleano aleatorio: en lugar de new java.util.Random().nextBoolean()que puedas usar Math.random()<.5.
Kevin Cruijssen

7

No sé si consideraría esta Java 'pura', pero Processing le permite crear programas con poca configuración inicial (completada automáticamente).

Para la salida de la consola, puede tener algo tan simple como:

println("hi"); //done

para salida gráfica, un poco más:

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! Me aseguraré de jugar con eso.
Rob

¿Estaría bien si agregara las respuestas de otras personas a esta? ¿O eso vence el propósito de una wiki comunitaria?
Rob

2
Por cierto, ni siquiera tiene que llamar sizeen absoluto; por defecto tendrá un cuadrado de 100 por 100 píxeles. En la mayoría de los sistemas operativos, el marco a su alrededor será aproximadamente el doble de grande, con el cuadrado centrado y el resto del área llena de contenido tomado del escritorio.
AJMansfield

1
Para la salida gráfica, si no necesita animación, puede escribir todo fuera setup()y draw()usar el "modo estático". También puede usar colores hexadecimales de 6 dígitos y el intérprete los cambiará, lo que a veces vale la pena ( #FF8000< 255,128,0), y si está usando escala de grises solo se debe especificar un número ( 255< 255,255,255)
quat

7

Acortamiento regresando

Puede acortar las declaraciones de retorno de cadenas por un byte con:

return "something";

a

return"something";

Y, si comienza su declaración de retorno con un paréntesis, puede hacer lo mismo con ellos:

return (1+taxRate)*value;

a

return(1+taxRate)*value;

¿Supongo que las citas se consideran paréntesis? De hecho, recogí esto a través de AppleScript, curiosamente, y pensé que valdría la pena mencionarlo.


1
Lo mismo se aplica a los signos numéricos, como en return-n;lugar de return -n;o en return~n;lugar de return ~n;. Además de comillas simples en lugar de dobles:return'A';
Kevin Cruijssen

1
Básicamente, funciona para cualquier cosa que no pueda ser parte de un identificador (es decir, sin letra y sin dígitos).
Paŭlo Ebermann

7

No tengas miedo de usar notación científica

Si se trata de dobles o flotadores, puede usar la notación científica para los números. Entonces, en lugar de escribir double a=1000, puede cambiarlo double a=1e3para guardar 1 byte.


7

Intenta usar en intlugar deboolean

En algunos casos, descubrí que es más corto devolver un valor entero de un método que normalmente devolvería un valor booleano, de manera similar a lo que se podría hacer en los programas en C.

De buenas a primeras intes 4 bytes más corto que boolean. Cada vez que escribe en return 0lugar de return 1<0, guarda 2 bytes adicionales y lo mismo para return 1 más return 1>0.

El problema aquí es que cada vez que desee utilizar el valor de retorno directamente como un valor booleano, cuesta 2 bytes ( if(p(n))v. if(p(n)>0)). Esto puede compensarse mediante el uso de la aritmética booleana. Dado un escenario artificial donde quieres escribir

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

en su lugar puedes escribir

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

para ahorrar 2 bytes.


66
Hago esto con bastante frecuencia cuando juego al golf, pero tenga en cuenta que el consenso general es eso 0y 1no constituye falso / verdadero en Java (y el JLS tampoco los considera de esa manera). Entonces, si el golf está pidiendo específicamente veracidad / falsedad, debe booleanizarlo (y, desafortunadamente, convertirlo en una booleanfunción, arrojándole aún más bytes).
Geobits

2
t[0]+=p(n):10?0;¿Es esto incluso válido?
dorukayhan

@dorukayhan no, está destinado a ser t[0]+=p(n)?10:0;. (Lo edité.)
Paŭlo Ebermann

6

Si usa enum en lugar de clase , guarda un personaje.

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

    }
}

Pero debe introducir al menos una instancia de enumeración (F, G, H en este ejemplo) que tienen que compensarse.


2
Parece que no necesita ninguna instancia de enumeración. Lo hice enum M{;public static void main(String[]a){...}sin problemas.
Danny

3
@Danny Pero entonces no guarda ningún personaje. class M{tiene exactamente la misma longitud que enum M{;. En ese caso, iría con el classporque es más bonito (IMO)
Justin

1
al menos para mí enum{trabajaba sin un ;después; es solo el IDE quejándose de que hay un error pero el compilador lo acepta
masterX244

@ masterX244 ¿Qué compilador / versión? El mío hace un berrinche y no lo hará.
Geobits

trabajé en Java 1.7 para mí (apareció para investigar la causa adicional con una actualización a .8 dejó de funcionar)
masterX244

5

Cuando tiene un método que debería devolver un booleano Boolean, es decir:

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

Puede cambiar el boolean/ Booleanreturn-type Objectpara guardar 1 byte:

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

Además, como habrá notado, puede usar un <1cheque en lugar de ==0guardar un byte. Aunque eso es más un consejo general de código de golf en lugar de específico de Java.
Esto se usa principalmente cuando el entero no puede ser negativo, como verificar la longitud:

a.length<1

en lugar de

a.length==0

1
Buen consejo! Es posible que desee agregar otro ejemplo en la sección "si no puede ser negativo" para ilustrarlo, ya que c(-21)regresa truecon el actual.
Geobits

Aclarado Además, ¿no quieres decir en c(-20)lugar de -21? -21 % 5 = 4y -20 % 5 = 0.
Kevin Cruijssen

1
No, quise decir -21. -21 % 5 != 4en Java, que es mi punto. El divisible por cinco función sería trabajar correctamente si el módulo siempre devueltos no negativo, pero no es así. Ver este fragmento de ejemplo .
Geobits

@Geobits Ah, gracias por el ejemplo. Casi nunca uso números negativos con %, así que olvidé que Java devuelve el resto en lugar del módulo, de ahí la diferencia ..
Kevin Cruijssen

5

Cómo dibujar en Java ...

Aquí está la placa de caldera de pintura GUI más corta posible:

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

Golfizado por 111 Bytes:

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

5

Evitar StringBuilders

Agregar cosas a un Stringocupa muchos menos bytes.

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

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

Si tiene que invertir una cadena e imprimirla de inmediato, 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

Si tiene que invertir una cadena y luego hacer algo más que imprimirla, use un forbucle.

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

3
Un bucle foreach es más corto que StringBufferpara invertir las cuerdas. String b="";for(char c:"Hello, World!".toCharArray()){b=c+b;}
Poke

1
También debe eliminar el {}bucle foreach si va a utilizar ese método.
Geobits

1
Ahorre 2 bytes usando en String s:"".split("")lugar de char c:"".toCharArray().
charlie

Si ya ha java.util.stream.Streamimportado y necesita encadenar otra llamada al resultado (como B.chartAt(42)) o si solo necesita pasar el resultado a una función (como f(B)), entonces usar for(:)es igual a Stream.of("Hello, World!".split("")).reduce("",(a,b)->b+a).
Charlie

Ambas líneas en su ejemplo con el para-cada se pueden jugar golf. El primero puede convertirse en: String b=new StringBuffer("Hello, World!").reverse()+"";( .toStringreemplazado por +""), y su segunda línea puede convertirse en: String B="";for(String c:"Hello, World!".split(""))B=c+B;( charhacia Stringy .toCharArray()hacia .split("")).
Kevin Cruijssen

5

Use Java 10's var

Si define una sola variable de un tipo específico, use var.

Ejemplos

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

No se puede usar en ninguno de los siguientes ejemplos

var no se puede usar en muchos ejemplos

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 qué esto no funciona con referencias de métodos, tenga en cuenta que hay interfaces funcionales estándar para solo un pequeño conjunto de firmas (y los métodos pueden arrojar excepciones marcadas).
Jakob


4

En la mayoría de los casos, su programa tendrá un solo subproceso, es decir, solo tendrá un subproceso en ejecución. Puede explotar este hecho returndesde el método principal cuando tiene que salir instantáneamente.

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

Compárelo con "correctamente" terminando el programa:

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

O apuntando a null:

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

O dividiendo por 0:

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

4

A veces, una sola instrucción for-loop puede ser reemplazable. Considere el siguiente código:

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

Este es un bucle for simple que es una solución a esta pregunta .

Como sabemos que ino será lo suficientemente grande como para causar errores de StackOverflow, podemos reemplazar el ciclo for con recursividad:

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

Podemos simular un bucle mediante el uso de un operador ternario en la declaración de retorno para causar recursividad.

Esta reducción es bastante específica, pero puedo imaginar más situaciones en las que esto sería útil.


4

Usando ...(varags) como parámetro

En algunos casos es más corto usar un varargs de Java como parámetro en lugar de los sueltos.
Por ejemplo:

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

Sería golfed por la mayoría de esto:

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

Pero se puede jugar un byte adicional a esto:

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

Tenga en cuenta que solo se accede a los tres enteros una vez en el método mismo. Como intes bastante corto, solo es beneficioso si los usa cada uno una vez dentro del método y tiene tres o más de ellos como parámetro.

Sin embargo, con parámetros más largos esto suele ser más útil. Por ejemplo, esta fue mi respuesta original para este desafío (calcular las ocurrencias del carácter de entrada en la cadena de entrada):

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

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

Y me recomendaron jugar golf para esto:

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

Pero terminé jugando golf a esto usando ...:

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

NOTA: Si la pregunta / desafío solicita una entrada flexible, ...se puede acortar a, []por supuesto. Si la pregunta / desafío específicamente pide, digamos, tres Stringentradas y no permite una Stringmatriz que contenga tres valores, puede usar en String...lugar de String a,String b,String c.


2
¿No puedes usar un en String[]lugar de usar varargs? (ahorra 1 byte más)
Kritixi Lithos

@KritixiLithos Hmm .. buen punto. Pero eso depende principalmente de cuán flexible sea la entrada para el desafío. Si se permite cualquier formato de entrada, ese sería de hecho más corto. Agregaré esto a estos consejos, gracias.
Kevin Cruijssen
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.