Conseils pour jouer au golf à Java


86

Existe-t-il des raccourcis utiles utilisables en Java?

Comme indiqué ci-dessous, importajoute déjà au moins 17 caractères à un programme.

import java.io.*;

Je comprends que la solution simple consisterait à utiliser un autre langage, mais raccourcir les programmes Java semble être un réel défi.


Les astuces doivent être spécifiques à Java: s’ils s’appliquent à la plupart des langages de type C, ils appartiennent à la liste plus générale d’astuces .


9
packagepeut être sauté.
st0le

Dans une réponse, ne puis-je pas simplement omettre les importations en supposant qu'elles sont là?
Fabricio

1
@Fabricio Non, à moins que l'OP ne le spécifie.
nyuszika7h

32
Meilleur conseil sur le golf en Java: ne l'utilisez pas. ;)
kirbyfan64sos

4
"Je veux
jouer

Réponses:


85
  • Utilisez le java le plus récent possible. Java 8 vous permet d' utiliser des expressions lambda, donc l' utiliser si vous avez besoin , même comme des objets fonctionnels.

  • Définissez des fonctions abrégées pour les choses que vous utilisez beaucoup. Par exemple, vous avez cent appels à exampleClassInstance.doSomething(someParameter), définir une nouvelle fonction void d(ParameterType p){exampleClassInstance.doSomething(p)}et l'utiliser pour vous épargner des caractères.

  • Si vous utilisez plusieurs fois un nom de classe long particulier, comme

    MyEventHandlerProxyQueueExecutorServiceCollectionAccessManagerFactory

    à la place, définissez une nouvelle classe:

    class X extends MyEventHandlerProxyQueueExecutorServiceCollectionAccessManagerFactory{}

    Si vous utilisez uniquement une méthode particulière de cette classe (mais que vous avez toujours besoin de l'instancier), vous pouvez définir une version abrégée à l'intérieur de la nouvelle classe en même temps.

  • Utilisez les paramètres de type de fonction pour raccourcir les choses, si possible, comme ceci:

    <T>void p(T o){System.out.println(o);}
  • Utilisez for(;;)au lieu de while(true).

  • N'utilisez pas de modificateurs d'accès, sauf en cas d'absolue nécessité.

  • Ne pas utiliser finalpour rien.

  • Ne mettez jamais un bloc après une forboucle (mais une boucle foreach for(x:y)est différente). Des déclarations supplémentaires doivent être placées dans la fordéclaration elle-même, comme for(int i=0;i<m;a(i),b(++i))c(i);.

  • Utilisez l'affectation en ligne, l'incrémentation, l'instanciation. Utilisez des classes en ligne anonymes, le cas échéant. Utilisez lambdas à la place si possible. Appels de fonction de nid. Certaines fonctions ont la garantie de retourner leur objet parent, celles-ci sont même censées être chaînées.

  • Votre mainméthode throws Exceptionne les attrape pas.

  • Errorest plus court que Exception. Si pour une raison quelconque vous avez vraiment besoin de throwmessages en haut de la pile, utilisez un Error, même s’il s’agit d’une situation parfaitement normale.

  • Si une condition nécessite une résiliation immédiate, utilisez int a=1/0;plutôt que throw null;ou System.exit(0);. Au moment de l'exécution, cela jette un fichier ArithmeticException. Si vous avez déjà une variable numérique dans votre code, utilisez-la à la place. (Si vous avez déjà import static java.lang.System.*;, aller avec exit(0);.)

  • Au lieu d'implémenter des interfaces, par exemple List<E>, étendez une classe enfant immédiate (ou pas si immédiate, le cas échéant), comme AbstractList<E>, qui fournit des implémentations par défaut de la plupart des méthodes et ne requiert que l'implémentation quelques pièces clés.

  • Écrivez d'abord votre code dans le code de la main, avec les nouvelles lignes, l'indentation et les noms de variables complets. Une fois que vous avez le code de travail, vous pouvez alors raccourcir les noms, déplacer les déclarations et ajouter des méthodes de raccourci. En écrivant longtemps pour commencer, vous vous donnez plus de possibilités de simplifier le programme dans son ensemble.

  • Comparez les optimisations alternatives à un élément de code, car la stratégie la plus optimale peut changer de façon spectaculaire en modifiant très peu le code. Par exemple:

    • Si vous avez seulement jusqu'à deux appels Arrays.sort(a), la façon la plus efficace est de l' appeler avec son nom complet, java.util.Arrays.sort(a).
    • Avec trois appels ou plus, il est plus efficace d'ajouter une méthode de raccourci void s(int[]a){java.util.Arrays.sort(a);}. Cela devrait toujours utiliser le nom qualifié complet dans ce cas. (Si vous avez besoin de plus d'une surcharge, vous le faites probablement mal.)
    • Toutefois, si votre code doit également copier un tableau à un moment donné (généralement avec une courte forboucle de golf, en l'absence d'une méthode de bibliothèque facilement accessible), vous pouvez en profiter Arrays.copyOfpour effectuer la tâche. Lorsque plusieurs méthodes sont utilisées et qu'il y a 3 appels ou plus, import static java.util.Arrays.*;la méthode la plus efficace consiste à faire référence à ces méthodes. Par la suite, si vous sortutilisez plus de 8 appels distincts, utilisez une méthode de raccourci, et seulement à 5 appels ou plus, un raccourci est garanti copyOf.

    Le seul moyen réel d'effectuer une telle analyse sur le code consiste à effectuer des modifications éventuelles sur des copies du code, puis à comparer les résultats.

  • Évitez d'utiliser la someTypeValue.toString();méthode, ajoutez simplement someTypeValue+"".

  • Si vous avez besoin de Windows, n'utilisez pas Swing, utilisez AWT (sauf si vous avez vraiment besoin de quelque chose de Swing). Comparez import javax.swing.*;et import java.awt.*;. De plus, les composants Swing ont un Jpréfixé à leur nom ( JFrame, JLabel, etc.), mais les composants dans AWT ne le font pas ( Frame, Label, etc.)


43

Utilisez interfaceau lieu de class.

En Java 8, des méthodes statiques ont été ajoutées aux interfaces. Dans les interfaces, toutes les méthodes sont publiques par défaut. par conséquent

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

peut maintenant être raccourci à

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

ce qui est évidemment plus court.

Par exemple, j'ai utilisé cette fonctionnalité dans Hello, World! défi.


8
Je ne savais pas ça! +1, belle astuce
HyperNeutrino

Oui, moins de passe-passe!
CalculatriceFeline

3
Je ne suis pas tout à fait d'accord (et je vous ai également battu dans le défi "Bonjour le monde!" Avec cette technique).
Olivier Grégoire

37

Avec varargs, vous pouvez " convertir " un paramètre en un tableau du même type:

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

au lieu de

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

31

Avec une importation statique :

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

vous pouvez économiser un peu plus tard, mais vous avez besoin de plusieurs invocations pour obtenir un gain:

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

8
: O. Tu peux le faire?! Et tout ce temps, j'ai pensé que c'était impossible Java!
Justin

12
vous pouvez même utiliser import static java.lang.System.*.
Johannes Kuhn

1
Je sais que c'est une vieille réponse, mais avec Java 10, vous pouvez maintenant le faire var o=System.out;et ne l'utilisez que deux fois avant que cela porte ses fruits
Luke Stevens

@ LukeStevens: Eh bien, peut-être trouverez-vous d'autres améliorations, possibles avec Java10, et formerez-vous une réponse distincte autour de Java10?
utilisateur inconnu

1
@ LukeStevens var o=System.out.printlnfonctionnerait?
MilkyWay90

25

L'argument à mainne doit pas nécessairement être appelé args, et vous pouvez couper certains espaces:

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

fera très bien.


1
Les réponses doivent-elles inclure la fonction principale si elle n’indique pas explicitement l’écriture d’un programme complet? J'ai utilisé des expressions lambda comme réponses.
Makotosan

3
@ Makotosan Non, ils ne le font pas; Les Lambdas sont généralement bien.
daniero

21

Si vous devez utiliser les expressions booléennes trueou false, remplacez-les par 1>0et 1<0respectivement.

Par exemple:

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

Cet exemple de recherche linéaire peut être réduit à

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

11
Si vous avez besoin de beaucoup de choses true/false, ajoutez simplement boolean t=1>0,f=1<0;. Puis, au lieu de 1>0, utilisez tet enregistrez deux caractères par utilisation. Le gain sur la 1>0méthode vient à 10 utilisations.
Geobits

24
@ Geobits: boolean t=1>0,f=!t;- un caractère plus court!
Bob

6
L'exemple n'est pas vraiment bon. Dans ce cas et dans beaucoup d'autres cas, vous pouvez éviter d'utiliser true/ falsedirectement: cela f|=a[i++]==42;économise beaucoup.
Ingo Bürk

@ IngoBürk True. Lorsque j'écrivais ceci, je pensais surtout aux fonctions de bibliothèque que booleanj'utilise, mais comme je ne pouvais pas donner d'exemples au moment de l'écriture (je ne code généralement pas en Java), je viens d'écrire un exemple simple.
ace_HongKongIndependence

1
@ Geobits ne connaît pas trop Java, mais pourriez-vous simplement définir 1 et utiliser t et! T (encore une fois, je ne connais pas Java, je suis juste curieux)
Albert Renshaw

20

Si vous utilisez beaucoup une méthode, affectez sa classe résidente à une variable. Par exemple, assignez System.outà une variable:

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

Aussi pour Integer.parseInt():

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

Cela déclenchera presque sûrement un avertissement concernant "l'accès à la méthode statique à partir d'une variable"


((Integer)1).parseInt("1")fonctionne aussi.
Urne Magique Octopus

5
@carusocomputing new Integer("1")est encore plus court. Mais ce que Justin voulait dire par sa réponse, c'est que vous pouvez réutiliser les variables que vous avez déjà pour les appels statiques. Comme je l'explique au bas de cette réponse.
Kevin Cruijssen

19

Plutôt que d’utiliser la import static java.lang.System.*technique pour économiser surprintln() instructions, j'ai constaté que la définition de la méthode suivante est beaucoup plus efficace pour enregistrer des caractères:

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

En effet, il peut être invoqué p(myString)plutôt que de out.println(myString)bénéficier d’un gain de caractère beaucoup plus rapide et spectaculaire.


19

Cela peut sembler évident, mais il existe des options plus courtes pour certaines Mathfonctions:

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 vous avez besoin de Integer.MAX_VALUE(2147483647), utilisez -1>>>1. Integer.MIN_VALUE(-2147483648) est mieux écrit 1<<31.


14

Si vous devez extraire un nombre d'un argument (ou de toute autre chaîne), vous verrez normalement quelque chose comme:

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

Plusieurs fois, vous n’avez pas besoin d’ un Integer. Beaucoup de défis n'utilisent pas de grands nombres. Étant donné Shortque Byteles deux seront décompressés en un int, utilisez le plus approprié valueOf()et enregistrez quelques octets.

Gardez votre variable réelle comme un int, cependant, car elle est plus courte que les deux byteet short:

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

Si vous devez le faire pour plusieurs numéros, vous pouvez combiner cette méthode :

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

9
int n=new Byte(a[0]);est trois plus court. Si le nombre est peut-être supérieur, utilisez-le long n=new Long(a[0]), il sera toujours meilleur que ints dans la plupart des cas.
Ypnypn

14

Ne pas utiliser public class. La méthode principale doit être publique, mais pas sa classe. Ce code fonctionne:

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

Vous pouvez courir java Smême si ce class Sn'est pas une classe publique. ( Mise à jour: j'utilisais Java 7 lorsque j'ai écrit cette astuce. En Java 8, votre méthode principale doit être dans une interface . En Java 5 ou 6, votre méthode principale doit être en enum .)

Beaucoup de programmeurs Java ne le savent pas! Environ la moitié des réponses à une question sur le dépassement de pile concernant une classe principale dans une classe non publique prétendent à tort que la méthode principale doit être une classe publique. Maintenant tu sais mieux. Supprimez le publicdans public classet enregistrez 7 caractères.


1
Sauf si vous ciblez une version de Java antérieure à 1.8, la construction interface s{static void main(String[]...est plus courte. Si vous devez avoir un fichier source compilable et une méthode principale. Comme dans une interface Java 1.8, toutes les méthodes sont publiques, vous pouvez donc ignorer le modificateur de la ou des méthodes.
Douglas Held

Je n'ai pas utilisé Java récemment, ma réponse est donc obsolète. J'ai oublié que les interfaces peuvent avoir des méthodes en Java 8.
kernigh

Je ne l'ai pas appris en programmant; Je l'ai appris en jouant au golf :)
Douglas Held

14

Quelques petits conseils de code-golf

Ces astuces étaient un peu trop petites pour une réponse séparée, je vais donc utiliser cette réponse pour de très petites astuces de golf-code que j'ai trouvées ou proposées, et qui ne sont pas encore mentionnées dans les autres astuces:

Supprimer le dernier caractère d'une chaîne:

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

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

Dans certains cas, vous savez à l’avance le dernier caractère et vous savez également que ce caractère n’apparaît qu’une fois dans la chaîne. Dans ce cas, vous pouvez utiliser à la .splitplace:

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

Raccourcis d'encodage:

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

Tous les encodages ont un nom canonique utilisé dans l' java.nioAPI, ainsi qu'un nom canonique utilisé dans les API java.ioet java.lang. Voici une liste complète de tous les encodages pris en charge en Java. Donc, utilisez toujours le plus court des deux; la seconde est généralement plus courte (comme UTF-8vs utf8, Windows-1252vs Cp1252, etc.), mais pas toujours ( UTF-16BEvs UnicodeBigUnmarked).

Booléen aléatoire:

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

Il existe différentes façons de rechercher des nombres premiers ou d'obtenir tous les nombres premiers, mais la réponse de @ SaraJ est la plus courte. Voici un copier-coller comme référence:

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

REMARQUE: En règle générale, vous pouvez le fusionner avec d'autres boucles existantes en fonction de la manière dont vous souhaitez l'utiliser. Vous n'avez donc pas besoin d'une méthode distincte. Cela a permis d'économiser beaucoup d'octets dans cette réponse, par exemple.

Troncature d'entier au lieu de Math.floor / Math.ceil:

Si vous utilisez des doubles / floats positifs et que vous souhaitez floorles utiliser, n'utilisez pas, Math.floormais utilisez (int)plutôt -cast (car Java tronque les entiers):

double d = 54.99;

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

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

// Outputs 54 for both

La même astuce peut être appliquée aux doublons / flotteurs négatifs que vous souhaitez utiliser à la ceilplace:

double d = -54.99;

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

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

// Outputs -54 for both

Utilisez &1au lieu de %2pour vous débarrasser des parenthèses:

Étant donné que la priorité de l' opérateur& est inférieure à celle des opérateurs arithmétiques par défaut tels que */+-et %, vous pouvez supprimer les parenthèses dans certains cas.

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

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

Notez que cela n'aide pas vraiment dans les contrôles booléens, car alors vous auriez toujours besoin de parenthèses, elles sont juste déplacées un peu:

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

BigIntegers et la création de variables pour les appels de méthodes statiques:

Lorsque vous utilisez BigIntegers, créez-le une seule fois, que vous pourrez ensuite réutiliser. Comme vous le savez peut-être, BigInteger contient des champs statiques pour ZERO, ONEet TEN. Ainsi, lorsque vous utilisez uniquement ces trois éléments, vous n’avez pas besoin d’un, importmais vous pouvez les utiliser java.Math.BigIntegerdirectement.

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

NOTE: Vous devez utiliser =nullainsi test initialisé pour pouvoir utiliser t..

Parfois, vous pouvez ajouter plusieurs BigIntegers pour en créer un autre afin de sauvegarder des octets. Alors disons que vous voulez avoir les BigIntegers 1,10,12pour une raison quelconque:

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

Comme correctement souligné dans les commentaires, l'astuce avec BigInteger t=null;ses appels de méthode statique peut également être utilisée avec d'autres classes.
Par exemple, cette réponse de 2011 peut être lue:

// 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() au lieu de toCharArray()

Lorsque vous souhaitez effectuer une boucle sur les caractères d'une chaîne, procédez comme suit:

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

Faire une boucle sur les caractères peut être utile pour les imprimer, les ajouter à une chaîne ou quelque chose de similaire.

Toutefois, si vous utilisez uniquement les caractères pour certains calculs de nombre unicode, vous pouvez remplacer le charavec int, ET vous pouvez le remplacer toCharArray()par getBytes():

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

Ou même plus court en Java 8+:

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

En Java 10+, le bouclage sur le caractère à imprimer peut maintenant aussi être effectué sur 22 octets:

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

Article aléatoire 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

Vérifier si une chaîne contient des espaces de début / fin

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

Pourquoi cela fonctionne-t-il, alors que !=sur Strings, il faut vérifier la référence au lieu de la valeur en Java? Car String#trimretournera " Une copie de cette chaîne avec les espaces blancs de début et de fin supprimés, ou cette chaîne si elle n'a pas d'espace blanc de début ou de fin . " Je l'ai utilisé, après que quelqu'un me l'ait suggéré, dans ma réponse .

Palindrome:

Pour vérifier si une chaîne est un palindrome (en gardant à l'esprit les longueurs paires et impaires des chaînes), il s'agit de la plus courte ( .containsfonctionne ici car nous savons que la chaîne elle-même et sa forme inversée sont de même longueur):

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

.contains(...)au lieu de .equals(...+"")grâce au commentaire de @assylias ici .

Soit 0, ou les deux sont 0?

Je pense que la plupart connaissent déjà celui-ci: si vous voulez vérifier si l'un aou l' autre best égal à zéro, multipliez-le pour sauvegarder les octets:

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

Et si vous voulez vérifier si les deux aet bsont égaux à zéro, vous pouvez utiliser un opérateur OR, ou les ajouter ensemble si elles sont toujours positives:

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)

Pair = 1, impair = -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

La raison pour laquelle j'ai ajouté ceci était après avoir vu k+(k%2<1?1:-1)dans cette réponse :

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

nTemps de boucle dans le programme complet

Si nous avons un défi pour lequel un programme complet est obligatoire et que nous devons boucler un nombre de fois spécifique, nous pouvons procéder comme suit:

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

Il en va de même lorsque nous devons prendre cette plage en entrée:

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

Merci à @JackAmmo pour ce commentaire .

try-finally au lieu de try-catch (Exception e) lors du retour et quand l'utiliser

Si vous ne pouvez pas utiliser un throws Exceptionmais devez le faire catchet y faire quelque chose avant de revenir, vous pouvez utiliser à la finallyplace:

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

En ce qui concerne un exemple d'utilisation d'un try-catch, je peux me référer à cette réponse (le crédit pour le golf indirect va à @KamilDrakari ). Dans ce défi, nous devons boucler en diagonale sur une matrice NxM, nous devons donc déterminer si le nombre de colonnes ou le nombre de lignes est le plus bas que notre maximum dans la boucle for (ce qui est assez coûteux en termes d'octets:) i<Math.min(a.length,a[0].length). Donc, attraper simplement l' ArrayIndexOutOfBoundsExceptionutilisation catch-finallyest plus court que cette vérification, et sauve ainsi des octets:

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

NOTE: Cela a seulement fonctionné à cause de return r;l'enfin. On m'a suggéré de modifier la première cellule, comme l'a fait @KamilDrakari dans sa réponse en C # pour économiser des octets. Cependant, en Java, cela signifie que je devrai le modifier en m->{try{for(int i=1;;m[0][0]=f(m[0][0],m[i][i++]));}catch(Exception e){}}(73 octets), ce qui augmenterait le nombre d'octets au lieu de diminuer si j'avais pu l'utiliser finally.

Math.pow (2, n)

Lorsque vous voulez une puissance de 2, une approche un peu sage est beaucoup plus courte:

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

Combinaison de contrôles binaires et logiques au lieu d'utiliser des parenthèses

Je pense qu'il est bien connu maintenant que &et |peut être utilisé à la place &&et ||en Java (Boolean) Les contrôles logiques. Dans certains cas, vous souhaiterez quand même utiliser &&au lieu de &pour éviter les erreurs, comme index >= 0 && array[index].doSomething. Si le &&serait changé à &ici, il évaluera toujours la partie où il utilise l'index dans le tableau, provoquant une ArrayIndexOutOfBoundsException, d'où l'utilisation de &&dans ce cas à la place de &.

Jusqu'ici, les bases de &&/ ||vs &/ |en Java.

Lorsque vous voulez vérifier (A or B) and C, le plus court peut sembler utiliser les opérateurs binaires comme celui-ci:

(A|B)&C    // 7 bytes

Toutefois, comme les opérateurs au niveau des bits ont priorité sur les contrôles logiques, vous pouvez combiner les deux pour enregistrer un octet ici:

A|B&&C     // 6 bytes

Utiliser n+=...-nau lieu de(long)...

Lorsque vous avez un long comme dans et sortie dans un lambda, par exemple lors de l'utilisation Math.pow, vous pouvez enregistrer un octet en utilisant à la n+=...-nplace de (long)....
Par exemple:

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

Cela a sauvé un octet dans cette réponse à moi , et même deux octets en combinant -n-1à +~ndans cette réponse à moi .


Plus généralement, pour votre dernier point, vous pouvez accéder à / invoquer des membres statiques à partir d'un contexte non statique tel qu'une instance de l'objet.
Poke

1
Je ne comprends pas votre astuce de plafond. Pourquoi voudriez-vous ceil positive integers? De plus, je ne suis pas sûr que la mise en œuvre de ceil fonctionne .
Jonathan Frech

1
since Java automatically floors on integers; Je pense que le terme approprié est troncature , pas revêtement de sol .
Jonathan Frech

1
Une autre stratégie PalindromeString t="";for(int i=s.length();--i>=0;t+=s.charAt(i));return s.equals(t);
Roberto Graham

1
@RobertoGraham J'ai en fait copié mon code original à partir du mauvais défi. Juste, s.equals(new StringBuffer(s).reverse()+"")c'est assez.
Kevin Cruijssen

11

Pour jouer au golf qui ne nécessite pas d’entrée, vous pouvez utiliser des blocs statiques et le lancer sans aucune méthode principale, il suffit de le compiler avec Java 6.

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

1
Avez-vous essayé de le compiler et de l'exécuter? Ce bloc est exécuté lorsque la classe est chargée par le chargeur de classes. Mais le chargeur de classes ne chargera rien tant qu'il ne saura pas qu'une classe utilise une méthode main.
Cruncher

@Cruncher Vous pouvez contourner ce problème en indiquant vous-même javasur la ligne de commande / dans un fichier manifeste la classe à charger.
AJMansfield

6
@Cruncher, cela fonctionnait avec Java 6. Java 7 a changé son fonctionnement.
Peter Taylor

1
Lance une exception à la fin mais ça marche! Même en Java 7
stommestack

2
@JopVernooij Si vous ne voulez pas avoir une exception à la face, vous pouvez system.exit (), mais vous perdez des personnages, aucun défi de golf ne vous demande d'éviter les exceptions;)
Fabinout

11

Nous connaissons tous le bitwise xor ( ^), mais c'est aussi un xor logique.

Alors (a||b)&&!(a&&b)devient tout simplement a^b.

Nous pouvons maintenant utiliser xor.

En outre , les opérateurs |et & travaillent également , rappelez-vous simplement que la priorité des opérateurs change.


5
Tant que vous vous souvenez de la priorité, vous pouvez utiliser & et |aussi. Cela peut être utile si vos conditions sont déjà entre parenthèses ou si vous travaillez déjà avec des booléens.
Geobits

1
Si vous avez besoin d'une (beaucoup) inférieure préséance, vous pouvez utiliser à la !=place de ^pour xor, et ==pour xnor
Cyoce

11

Vous n'êtes pas obligé d'utiliser Character.toLowerCase(char c). Utilisez plutôt (c|32). Au lieu d' Character.toUpperCase(char c)utiliser (c&~32). Cela ne fonctionne qu'avec les lettres ASCII.


c|~32aurait tendance à se traduire par -1 ... mieux à utiliser c-32.
Feersum

5
@feersum Cela ne fonctionnerait pas si vous vouliez faire une majuscule.
TheNumberOne

11

Convertir une chaîne en nombre

Il existe plusieurs façons de convertir une chaîne en valeur numérique:

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

nouvel ABC :

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

Ainsi, pour le code-golf, il est préférable d'utiliser le constructeur lors de la conversion d'une chaîne en valeur numérique.

La même chose s'applique à Double; Float; et Byte.


Cela ne s'applique pas toujours lorsque vous pouvez réutiliser une primitive déjà présente en tant qu'objet.
Par exemple, supposons que nous avons le code suivant:

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

Vous pouvez utiliser .decodele constructeur plus court en réutilisant le paramètre en tant qu'objet:

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

Ne pas utiliser Random!

En général, si vous avez besoin de nombres aléatoires, Randomc'est une façon horrible de s'y prendre *. Mieux vaut utiliser à la Math.random()place. Pour l'utiliser Random, vous devez faire ceci (disons qu'il nous faut un int):

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

Comparez cela à:

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

et:

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

La première méthode prend des 41+15ncaractères ( nc'est le nombre d'appels). La seconde est des 25npersonnages, et la troisième est43+7n .

Donc, si vous n'en avez besoin qu'une ou deux fois, utilisez la Math.random()méthode inline . Pour trois appels ou plus, vous enregistrez en utilisant une fonction. Soit on enregistre des caractères sur la première utilisation plus Random.


Si vous utilisez déjà Math.random()pour double, rappelez-vous qu’au bout de quatre utilisations, il reste des économies à réaliser:

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

Pour 33 caractères, vous en économiserez 10 à chaque appel de r()


Mise à jour

Si vous avez besoin d'un entier et que vous souhaitez économiser sur le casting, ne le lancez pas! Java se lance automatiquement si vous effectuez une opération au lieu d'une affectation. Comparer:

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

* Sauf si vous devez semer le PRNG pour obtenir des résultats prévisibles. Ensuite, je ne vois pas beaucoup de chemin autour de ça.


2
N'oubliez pas Random#nextGaussiancependant.
Justin

@Quincunx C'est vrai, faire le calcul pour obtenir une bonne distribution normale vous ferait perdre toutes les économies que vous auriez obtenues. Je ferai simplement référence à cela comme à l'exception qui
confirme

Notez que le (int)(Math.random()*9)biais modulo est très faible, car Math.random()renvoie 2 53 valeurs possibles et 2 53 n'est pas un multiple de 9. La probabilité de chaque nombre est inférieure à 1/9 plus ou moins 5 / (9 * 2 ** 53), une erreur si petite, c'est presque exactement 1/9.
Kernigh

@kernigh D'accord, j'utilisais 9juste à titre d'exemple, cela pouvait être n'importe quoi. Je suis relativement sûr que nextInt()(ou toute autre Randomméthode) présente également un léger biais, juste en raison du fonctionnement du PRNG de Java.
Geobits

1
Quelque chose de lié pour quand vous voulez un booléen aléatoire: au lieu de new java.util.Random().nextBoolean()vous pouvez utiliser Math.random()<.5.
Kevin Cruijssen

7

Je ne sais pas si vous considéreriez ce Java «pur», mais Processing vous permet de créer des programmes avec une configuration initiale réduite (terminée automatiquement).

Pour la sortie de la console, vous pouvez avoir quelque chose d'aussi simple que:

println("hi"); //done

pour la sortie graphique, un peu plus:

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 excellente ressource! Je vais être sûr de jouer avec ça.
Rob

Est-ce que ça irait si j'y ajoutais les réponses d'autres personnes? Ou est-ce que cela va à l'encontre du but d'un wiki de communauté?
Rob

2
En passant, vous n’avez même pas à appeler sizedu tout; il utilisera par défaut un carré de 100 x 100 pixels. Dans la plupart des systèmes d’exploitation, le cadre qui l’entoure sera environ deux fois plus grand, avec le carré centré et le reste de la zone rempli de contenu pris sur le bureau.
AJMansfield

1
Pour une sortie graphique, si vous n'avez pas besoin d'animation, vous pouvez simplement écrire tout en dehors de setup()et draw()utiliser le "mode statique". Vous pouvez également utiliser des couleurs hexadécimales à 6 chiffres et l'interprète les modifiera, ce qui est parfois payant ( #FF8000< 255,128,0), et si vous utilisez l'échelle de gris, vous ne devez spécifier qu'un seul nombre ( 255< 255,255,255)
quat

7

Raccourcissement de retour

Vous pouvez raccourcir les instructions de retour de chaînes par un octet avec:

return "something";

à

return"something";

Et, si vous commencez votre déclaration de retour par une parenthèse, vous pouvez faire la même chose avec elles:

return (1+taxRate)*value;

à

return(1+taxRate)*value;

Je suppose que les citations sont considérées comme des parenthèses? En fait, j’ai pris cela au sérieux grâce à AppleScript et j’ai pensé que cela valait la peine d’être mentionné.


1
Il en va de même pour les signes numériques, comme return-n;au lieu de return -n;ou à la return~n;place de return ~n;. Outre les guillemets simples au lieu des guillemets doubles:return'A';
Kevin Cruijssen le 21/09/17

1
Fondamentalement, fonctionne pour tout ce qui ne peut pas faire partie d'un identifiant (c'est-à-dire non lettre et non chiffre).
Paŭlo Ebermann

7

N'ayez pas peur d'utiliser la notation scientifique

Si vous avez affaire à des doubles ou à des flottants, vous pouvez utiliser la notation scientifique pour les nombres. Donc, au lieu d'écrire, double a=1000vous pouvez le changer double a=1e3pour sauvegarder 1 octet.


7

Essayez d'utiliser int au lieu deboolean

Dans certains cas, j'ai constaté qu'il est plus court de renvoyer une valeur entière à partir d'une méthode qui normalement renverrait un booléen, de la même manière que ce qui pourrait être fait dans les programmes C.

Dès le départ, la taille intest 4 octets plus courte que boolean. Chaque fois que vous écrivez à la return 0place de return 1<0, vous enregistrez 2 octets supplémentaires et la même chose pour return 1 over return 1>0.

Le piège est que chaque fois que vous voulez utiliser la valeur de retour directement comme un booléen, cela coûte 2 octets ( if(p(n))v. if(p(n)>0)). Ceci peut être compensé par l'utilisation de l'arithmétique booléenne. Étant donné un scénario artificiel où vous voulez écrire

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

vous pouvez plutôt écrire

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

afin d'économiser 2 octets.


6
Je le fais assez souvent quand le golf, mais gardez à l' esprit que le consensus général est que , 0et 1ne constituent pas faux / vrai en Java (et JLS ne les considère pas comme ça non plus ). Donc, si le golf demande spécifiquement la vérité / la fausseté, vous devez le booleaniser (et, malheureusement, en faire une booleanfonction, en jetant encore plus d'octets).
Geobits

2
t[0]+=p(n):10?0;Est-ce même valable?
Dorukayhan

@ dorukayhan non, c'est censé l'être t[0]+=p(n)?10:0;. (Je l'ai édité.)
Paŭlo Ebermann

6

Si vous utilisez enum au lieu de classe , vous enregistrez un caractère.

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

    }
}

Mais vous devez introduire au moins une instance enum (F, G, H dans cet exemple) qui doivent être rentables.


2
On dirait que vous n'avez pas besoin d'instances enum. Je l'ai fait enum M{;public static void main(String[]a){...}sans problèmes.
Danny

3
@Danny Mais alors cela n'enregistre aucun personnage. class M{est exactement la même longueur que enum M{;. Dans ce cas, j'irais avec classparce que c'est plus joli (IMO)
Justin

1
au moins pour moi a enum{travaillé sans un ;après; c'est le seul IDE gémissant qu'il y ait une erreur mais le compilateur l'accepte
masterX244

@ masterX244 Quel compilateur / version? Le mien pique une colère et ne le fera pas.
Geobits

a travaillé sur java 1.7 pour moi (il est apparu nécessaire pour rechercher une cause ultérieure avec une mise à jour de .8, il a cessé de fonctionner)
masterX244 le

5

Quand vous avez une méthode qui devrait retourner un booleanou Boolean, c'est-à-dire:

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

Vous pouvez changer le type boolean/ Booleanreturn Objectpour enregistrer 1 octet:

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

De plus, comme vous l'avez peut-être remarqué, vous pouvez utiliser une <1vérification au lieu de ==0sauvegarder un octet. Bien que ce soit plus un conseil de code-golf général au lieu de spécifique à Java.
Ceci est principalement utilisé lorsque le nombre entier ne peut pas être négatif, comme pour vérifier la longueur:

a.length<1

au lieu de

a.length==0

1
Bon conseil! Vous voudrez peut-être ajouter un autre exemple dans la section "si cela ne peut pas être négatif" pour l'illustrer, car c(-21)retourne trueavec le fichier actuel.
Geobits

Clarifié. Aussi, tu ne veux pas dire c(-20)au lieu de -21? -21 % 5 = 4et -20 % 5 = 0.
Kevin Cruijssen le

1
Non, je voulais dire -21. -21 % 5 != 4en Java, ce qui est mon point. Le divisible par cinq fonction serait fonctionner correctement si le module toujours retourné non-négatif, mais il ne fonctionne pas. Voir cet exemple d'extrait .
Geobits

@ Geobits Ah, merci pour l'exemple. Je n'utilise presque jamais de nombres négatifs avec %, j'ai donc oublié que Java renvoie le reste au lieu du module, d'où la différence ..
Kevin Cruijssen

5

Comment dessiner en Java ...

Voici la plaque de chaudière de peinture GUI la plus courte possible:

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

Golfé pour 111 octets:

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

5

Éviter StringBuilder s

Ajouter des éléments à a Stringprend beaucoup moins d'octets.

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

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

Si vous devez inverser une chaîne et l’imprimer immédiatement, utilisez 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 vous devez inverser une chaîne et faire autre chose que de l’imprimer, utilisez une forboucle chaque.

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

3
Une boucle foreach est plus courte que StringBufferpour l’inversion de chaînes. String b="";for(char c:"Hello, World!".toCharArray()){b=c+b;}
Poke

1
Vous devriez également supprimer le {}de cette boucle foreach si vous utilisez cette méthode.
Geobits

1
Sauvegardez 2 octets en utilisant String s:"".split("")au lieu de char c:"".toCharArray().
Charlie

Si vous avez java.util.stream.Streamdéjà importé et si vous devez chaîner un autre appel vers le résultat (du type B.chartAt(42)) ou si vous devez simplement transmettre le résultat à une fonction (du type f(B)), utilisez for(:)est égal à Stream.of("Hello, World!".split("")).reduce("",(a,b)->b+a).
Charlie

Les deux lignes de votre exemple avec le pour-chacun peuvent être jouées au golf. La première peut devenir: String b=new StringBuffer("Hello, World!").reverse()+"";( .toStringremplacé par +""), et votre deuxième ligne peut devenir: String B="";for(String c:"Hello, World!".split(""))B=c+B;( charto Stringet .toCharArray()to .split("")).
Kevin Cruijssen

5

Utiliser Java 10 var

Si vous définissez une seule variable d'un type spécifique, utilisez var.

Exemples

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 utilisable dans les exemples suivants

var ne peut pas être utilisé dans de nombreux exemples

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)

Si cela ne fonctionne pas avec les références de méthodes, notez qu'il existe des interfaces fonctionnelles standard pour un petit ensemble de signatures (et que les méthodes peuvent générer des exceptions vérifiées).
Jakob


4

Dans la plupart des cas, votre programme sera mono-thread, c'est-à-dire qu'un seul thread sera en cours d'exécution. Vous pouvez exploiter ce fait en returnutilisant la méthode principale lorsque vous devez quitter instantanément.

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

Comparez-le à "correctement" terminer le programme:

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

Ou pointant vers null:

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

Ou en divisant par 0:

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

4

Parfois, une seule instruction for-loop peut être remplacée. Considérons le code suivant:

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

Ceci est une simple boucle for qui est une solution à cette question .

Puisque nous savons que icela ne sera pas assez important pour causer des erreurs StackOverflow, nous pouvons remplacer la boucle for par une récursivité:

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

Nous pouvons simuler une boucle en utilisant un opérateur ternaire dans l'instruction return pour provoquer la récursivité.

Cette réduction est assez spécifique, mais je peux imaginer plus de situations où cela serait utile.


4

En utilisant ... (varags) comme paramètre

Dans certains cas, il est plus court d’utiliser un varargs Java en tant que paramètre plutôt que des paramètres non structurés.
Par exemple:

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

Serait le plus joué au golf à ceci:

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

Mais peut être joué un octet supplémentaire à ceci:

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

Notez que les trois entiers ne sont accessibles qu'une seule fois dans la méthode elle-même. Comme il intest assez court, il n’est utile que de les utiliser une seule fois dans la méthode et d’en avoir trois ou plus comme paramètre.

Avec des paramètres plus longs, cela est généralement plus utile. Par exemple, c’était ma réponse initiale à ce défi (calculer les occurrences du caractère saisi dans la chaîne de saisie):

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

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

Et on m'a recommandé de jouer au golf à ceci:

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

Mais j'ai fini par y mettre le golf en utilisant ...:

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

NOTE: Si la question / défi demande une entrée flexible, ...on peut []bien sûr le raccourcir . Si la question / défi demande spécifiquement, disons, trois Stringentrées et interdit un Stringtableau contenant trois valeurs, vous pouvez utiliser à la String...place de String a,String b,String c.


2
Vous ne pouvez pas utiliser un String[]au lieu d'utiliser varargs? (sauvegarde 1 octet de plus)
Kritixi Lithos

@KritixiLithos Hmm .. bon point. Mais cela dépend principalement de la flexibilité de la contribution au défi. Si un format d'entrée est autorisé, il serait effectivement plus court. Je vais ajouter ceci à ces conseils, merci.
Kevin Cruijssen
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.