Советы по игре в гольф на Яве


86

Есть ли полезные ярлыки, которые можно использовать в Java?

Как показано ниже, importуже добавляет не менее 17 символов в программу.

import java.io.*;

Я понимаю, что простым решением было бы использование другого языка, но, похоже, реальная проблема заключается в сокращении программ на Java.


Подсказки должны быть специфичны для Java: если они применимы к большинству языков, подобных C, они относятся к более общему списку советов .


9
packageможно пропустить
st0le

В ответ не могу ли я просто опустить импорт, если он там есть?
Fabricio

1
@Fabricio Нет, если это не указано в OP.
nyuszika7h

32
Лучший совет по поводу игры в гольф на Java: не используйте его. ;)
kirbyfan64sos

4
«Я хочу в гольф в Яве» удачи
sagiksp

Ответы:


85
  • Используйте самую последнюю возможную Java. Java 8 позволяет вам использовать лямбда-выражения, поэтому используйте его, если вам нужно что-то, даже как функциональные объекты.

  • Определите сокращенные функции для вещей, которые вы часто используете. Например, у вас есть сотня вызовов exampleClassInstance.doSomething(someParameter), определите новую функцию void d(ParameterType p){exampleClassInstance.doSomething(p)}и используйте ее, чтобы сохранить себе несколько символов.

  • Если вы используете определенное длинное имя класса более одного раза, например

    MyEventHandlerProxyQueueExecutorServiceCollectionAccessManagerFactory

    вместо этого определите новый класс:

    class X extends MyEventHandlerProxyQueueExecutorServiceCollectionAccessManagerFactory{}

    Если вы используете только один конкретный метод этого класса (но вам все еще нужно создать его экземпляр), вы можете одновременно определить сокращенную версию внутри нового класса.

  • Используйте параметры типа функции для сокращения, где это возможно, таких как:

    <T>void p(T o){System.out.println(o);}
  • Используйте for(;;)вместо while(true).

  • Не используйте модификаторы доступа без крайней необходимости.

  • Не используйте finalни для чего.

  • Никогда не ставьте блок после forцикла (но цикл foreach for(x:y)отличается). Дополнительные заявления должны быть помещены в самом forутверждении, как for(int i=0;i<m;a(i),b(++i))c(i);.

  • Используйте встроенное присваивание, приращение, создание экземпляров. При необходимости используйте анонимные встроенные классы. Вместо этого используйте лямбды, если это возможно. Вызов функции гнезда. Некоторые функции гарантированно возвращают свой родительский объект, эти фактически даже предназначены для объединения в цепочку.

  • Твой mainметод твои throws Exception, а не ловит их.

  • Errorкороче чем Exception. Если по какой-то причине вам действительно нужно throwотправить сообщения в стек, используйте Error, даже если это совершенно нормальная ситуация.

  • Если какое-либо условие потребует немедленного прекращения, используйте int a=1/0;вместо throw null;или System.exit(0);. Во время выполнения это бросает ArithmeticException. Если в вашем коде уже есть числовая переменная, используйте ее. (Если у вас уже есть import static java.lang.System.*;, идти с exit(0);.)

  • Вместо реализации интерфейсов, таких как List<E>, расширяйте непосредственный (или не очень немедленный, если есть какое-либо преимущество в этом вообще) дочерний класс, например AbstractList<E>, который обеспечивает реализации большинства методов по умолчанию и требует только реализации несколько ключевых частей.

  • Сначала напишите свой код от руки, с символами новой строки, отступами и полными именами переменных. Если у вас есть рабочий код, вы можете сокращать имена, перемещать объявления и добавлять ярлыки. Написав это долго, вы даете себе больше возможностей упростить программу в целом.

  • Сравните альтернативные варианты оптимизации с фрагментом кода, поскольку наиболее оптимальная стратегия может кардинально измениться при очень небольших изменениях кода. Например:

    • Если у вас есть только до двух вызовов Arrays.sort(a), самый эффективный способ - это позвонить с полностью определенным именем java.util.Arrays.sort(a).
    • При трех или более вызовах более эффективно вместо этого добавить метод ярлыка void s(int[]a){java.util.Arrays.sort(a);}. В этом случае все равно следует использовать полное имя. (Если вам нужно более одной перегрузки, вы, вероятно, делаете это неправильно.)
    • Однако, если вашему коду необходимо также скопировать массив в какой-то момент (обычно это делается с помощью короткого forцикла в гольфе, в отсутствие легкодоступного библиотечного метода), вы можете воспользоваться Arrays.copyOfэтой задачей. Когда используется более одного метода и имеется 3 или более вызовов, выполнение import static java.util.Arrays.*;является наиболее эффективным способом обращения к этим методам. После этого, только если у вас есть более 8 отдельных вызовов, sortвы должны использовать для него ярлык, и только для 5 или более звонков это оправдано copyOf.

    Единственный реальный способ выполнить такой анализ кода - это выполнить потенциальные модификации копий кода, а затем сравнить результаты.

  • Избегайте использования someTypeValue.toString();метода, просто добавьте someTypeValue+"".

  • Если вам нужны окна, не используйте Swing, используйте AWT (если вам действительно не нужно что-то из Swing). Сравните import javax.swing.*;и import java.awt.*;. Кроме того, компоненты в Swing имеют Jпрефикс перед своим именем ( JFrame, JLabelи т. Д.), А компоненты в AWT - нет ( Frame, Labelи т. Д.)


43

Используйте interfaceвместо class.

В Java 8 статические методы были добавлены к интерфейсам. В интерфейсах все методы общедоступны по умолчанию. вследствие этого

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

Теперь можно сократить до

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

что, очевидно, короче.

Например, я использовал эту функцию в Hello, World! вызов.


8
Я этого не знал! +1, хороший трюк
HyperNeutrino

Угу, меньше шаблонов!
CalculatorFeline

3
Я должен частично не согласиться (также я побил тебя в конкурсе «Здравствуй, мир!», Используя эту технику).
Оливье Грегуар

37

С помощью varargs вы можете «привести» параметр к массиву того же типа:

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

вместо

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

31

При статическом импорте :

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

Вы можете сохранить некоторые шаблоны позже, но вам нужно несколько вызовов для достижения результата:

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

8
: O. Ты можешь сделать это?! И все это время я думал, что это невозможно Java!
Джастин

12
Вы даже можете использовать import static java.lang.System.*.
Йоханнес Кун

1
Я знаю, что это старый ответ, но в Java 10 теперь вы можете делать то, var o=System.out;что нужно только дважды использовать, прежде чем оно окупится
Люк Стивенс

@LukeStevens: Ну, может, вы найдете какие-то другие улучшения, возможно с Java10, и сформируете отдельный ответ вокруг Java10?
пользователь неизвестен

1
@ LukeStevens будет var o=System.out.printlnработать?
MilkyWay90

25

mainНе нужно вызывать аргумент to args, и вы можете сократить пробелы:

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

все будет хорошо.


1
Должны ли ответы включать основную функцию, если в ней явно не указано, что нужно писать полную программу? Я использовал лямбда-выражения в качестве ответов.
Макотосан

3
@ Makotosan Нет, они не делают; Лямбды обычно в порядке.
Даниеро

21

Если вам когда-либо придется использовать логические выражения trueили false, замените их на 1>0и 1<0соответственно.

Например:

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

Этот пример линейного поиска может быть уменьшен до

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

11
Если вам нужно много true/false, просто добавьте boolean t=1>0,f=1<0;. Тогда вместо того 1>0, чтобы использовать tи сохранить два символа за использование. Выплата по 1>0методу прибывает в 10 использований.
Geobits

24
@Geobits: boolean t=1>0,f=!t;- один символ короче!
Боббель

6
Пример не очень хороший. В этом случае и многих других (!) Вы можете избежать использования true/ falseнапрямую в любом случае: f|=a[i++]==42;экономит довольно много.
Инго Бюрк,

@ IngoBürk Правда. Когда я писал это, я в основном думал о библиотечных функциях, которые используют boolean, но так как я не мог придумать никаких примеров во время написания (я обычно не пишу код на Java), я просто написал простой пример.
ace_HongKongIndependence

1
@Geobits не слишком знаком с Java, но вы могли бы просто определить 1 и использовать t и! T (опять же, я не знаю Java, просто любопытно)
Альберт Реншоу

20

Если вы собираетесь часто использовать какой-либо метод, присвойте его резидентный класс переменной. Например, присвойте System.outпеременную:

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

Также для Integer.parseInt():

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

Это почти наверняка вызовет предупреждение ide о «доступе к статическому методу из переменной».


((Integer)1).parseInt("1")тоже работает
Волшебная урна осьминога

5
@carusocomputing new Integer("1")еще короче. Но Джастин имел в виду, что его ответом является то, что вы можете повторно использовать переменные, которые у вас уже есть для статических вызовов. Как я объясню внизу этого ответа.
Кевин Круйссен,

19

Вместо того чтобы использовать import static java.lang.System.*технику для экономии на println()операторах, я обнаружил, что определение следующего метода гораздо более эффективно для сохранения символов:

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

Это потому, что это может быть вызвано тем p(myString), out.println(myString)что имеет гораздо более быстрый и драматический характер.


19

Это может показаться очевидным, но для некоторых Mathфункций есть более короткие варианты :

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

Если вам нужно Integer.MAX_VALUE(2147483647), используйте -1>>>1. Integer.MIN_VALUE(-2147483648) лучше написано 1<<31.


14

Если вам нужно получить число из аргумента (или любой другой строки), обычно вы видите что-то вроде:

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

Много раз, вам не нужноInteger . Много проблем не используют большие числа. Поскольку Shortи Byteоба будут распакованы int, используйте более подходящее valueOf()и сохраните пару байтов.

Сохраните фактическую переменную как int, хотя, так как она короче, чем оба byteи short:

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

Если вам нужно сделать это для нескольких номеров, вы можете комбинировать этот метод :

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

9
int n=new Byte(a[0]);в три раза короче Если число может быть больше, используйте long n=new Long(a[0]), intв большинстве случаев оно все же лучше, чем s.
Ypnypn

14

Не используйте public class. Основной метод должен быть публичным, а его класс - нет. Этот код работает:

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

Вы можете бежать, java Sдаже если class Sэто не публичный класс. ( Обновление: я использовал Java 7, когда писал этот совет. В Java 8 ваш основной метод должен быть в интерфейсе . В Java 5 или 6 ваш основной метод должен быть в перечислении .)

Многие программисты на Java этого не знают! Около половины ответов на вопрос Stack Overflow о main в непубличном классе ошибочно утверждают, что метод main должен быть в публичном классе. Теперь ты знаешь лучше. Удалить publicв public classи сохранить 7 символов.


1
Если вы не нацелены на Java до 1.8, конструкция interface s{static void main(String[]...будет короче. Если вы должны иметь скомпилированный исходный файл и метод main. Поскольку в интерфейсе Java 1.8 все методы являются общедоступными, вы можете пропустить модификатор метода (ов).
Дуглас

Я недавно не использовал Java, поэтому мой ответ устарел. Я забыл, что интерфейсы могут иметь методы в Java 8.
Kernigh

Я не изучал это от программирования; Я узнал это от игры в гольф :)
Дуглас провел

14

Несколько небольших советов по игре в гольф

Эти советы были слишком малы для отдельных ответов, поэтому я буду использовать этот ответ для очень маленьких советов по поиску кода, которые я нашел или придумал, и пока не упоминается в других советах:

Удаление последнего символа строки:

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

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

В некоторых случаях вы заранее знаете, какой последний символ, и также знаете, что этот символ встречается в строке только один раз. В этом случае вы можете использовать .splitвместо:

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

Сочетания клавиш:

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

Все кодировки имеют каноническое имя, используемое в java.nio API, а также каноническое имя , используемое в java.ioи java.langAPI. Вот полный список всех поддерживаемых кодировок в Java. Поэтому всегда используйте самый короткий из двух; вторая обычно короче (как UTF-8против utf8, Windows-1252против Cp1252и т. д.), но не всегда ( UTF-16BEпротив UnicodeBigUnmarked).

Случайный логический:

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

Штрихи:

Есть много разных способов проверить простые числа или получить все простые, но ответ @ SaraJ здесь самый короткий. Вот копия-вставка в качестве ссылки:

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

ПРИМЕЧАНИЕ. Обычно вы можете объединить его с другими существующими циклами в зависимости от того, как вы хотите его использовать, поэтому вам не понадобится отдельный метод. Это сэкономило много байтов в этом ответе, например.

Целочисленное усечение вместо Math.floor / Math.ceil:

Если вы используете положительный double / float и хотите floorих использовать, не используйте, Math.floorа (int)вместо этого используйте -cast (поскольку Java усекает целые числа):

double d = 54.99;

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

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

// Outputs 54 for both

Тот же трюк может быть применен к отрицательным двойным / плавающим числам, которые вы хотитеceilвместо этого:

double d = -54.99;

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

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

// Outputs -54 for both

Используйте &1вместо того, %2чтобы избавиться от скобок:

Поскольку оператор Внеочередной из &ниже арифметических операторов по умолчанию , как*/+- и %вы можете избавиться от скобок в некоторых случаях.

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

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

Обратите внимание, что это не очень помогает в булевых проверках, потому что тогда вам все еще понадобятся скобки, они просто немного сдвинуты:

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

BigIntegers и создание переменных для вызовов статических методов:

При использовании BigIntegers, создайте его только один раз, который затем сможете использовать повторно. Как вы знаете, BigInteger содержит статические поля для ZERO, ONEи TEN. Поэтому, когда вы используете только эти три, вам не нужно, importно можете использовать java.Math.BigIntegerнапрямую.

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

ПРИМЕЧАНИЕ: вы должны использовать =nullтакt инициализировано для использования t..

Иногда вы можете добавить несколько BigIntegers, чтобы создать другой для сохранения байтов. Допустим, вы хотите иметь BigIntegers 1,10,12по какой-то причине:

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

Как правильно указано в комментариях, трюк с BigInteger t=null;вызовами статических методов также можно использовать с другими классами.
Например, этот ответ с 2011 года может быть гольфом:

// 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() вместо toCharArray()

Когда вы хотите зациклить символы строки, вы обычно делаете это:

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

Циклы по символам могут быть полезны при их печати, или добавлении их в строку, или что-то подобное.

Однако, если вы используете только символы для некоторых расчетов юникода-номер, вы можете заменить charс int, и вы можете заменить toCharArray()с getBytes():

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

Или даже короче в Java 8+:

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

В Java 10+ зацикливание на символе для печати теперь также может выполняться в 22 байта:

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

Случайный предмет из 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

Проверьте, содержит ли строка начальные / конечные пробелы

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

Почему это работает, когда !=в Strings нужно проверять ссылку, а не значение в Java? Потому String#trimчто вернет « Копию этой строки с удаленными начальным и конечным пробелами, или эту строку, если у нее нет начальных или конечных пробелов» . Я использовал это после того, как кто-то предложил мне это, в этом моем ответе .

Палиндром:

Чтобы проверить, является ли String палиндромом (имея в виду как четные, так и нечетные длины строк), это самое короткое ( .containsработает здесь, потому что мы знаем, что и сама строка, и ее обращенная форма имеют одинаковую длину):

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

.contains(...)а не .equals(...+"")благодаря комментарию @assylias здесь .

Либо 0, либо оба 0?

Я думаю, что большинство уже знают это: если вы хотите проверить, равен aили bравен нулю, умножьте вместо этого, чтобы сохранить байты:

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

И если вы хотите проверить , равны ли оба aи bравны нулю, вы можете использовать побитовое ИЛИ или сложить их вместе, если они всегда положительны:

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)

Четный = 1, нечетный = -1; или наоборот

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

Поэтому я добавить это после того, как видит k+(k%2<1?1:-1)в этом ответе :

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

петля nВремя в полной программе

Если у нас есть проблема, когда полная программа обязательна, и нам нужно выполнить определенное количество циклов, мы можем сделать следующее:

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

То же самое относится, когда мы должны принять этот диапазон в качестве входных данных:

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

Кредит @JackAmmo в этом комментарии .

try-finally вместо try-catch (исключение e) при возврате и когда его использовать

Если вы не можете использовать a, throws Exceptionно должны catchи что-то сделать с ним до возвращения, вы можете использовать finallyвместо этого:

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

Что касается примера того, когда использовать a try-catch, я могу сослаться на этот мой ответ (кредит на косвенный гольф идет в @KamilDrakari ). В этой задаче мы должны по диагонали зациклить матрицу NxM, поэтому мы должны определить, является ли количество столбцов или количество строк наименьшим, как наш максимум в цикле for (что довольно дорого с точки зрения байтов:) i<Math.min(a.length,a[0].length). Таким образом, простое отслеживание ArrayIndexOutOfBoundsExceptionиспользования catch-finallyкороче, чем эта проверка, и, таким образом, сохраняет байты:

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

ПРИМЕЧАНИЕ. Это сработало только из- return r;за окончательного варианта. Мне предложили изменить первую ячейку, как @KamilDrakari в своем ответе на C #, чтобы сохранить байты. Однако в Java это означает, что мне придется изменить его на m->{try{for(int i=1;;m[0][0]=f(m[0][0],m[i][i++]));}catch(Exception e){}}(73 байта), фактически увеличивая количество байтов вместо уменьшения, если бы я мог использоватьfinally .

Math.pow (2, п)

Когда вы хотите степень 2, побитовый подход намного короче:

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

Объединение битовых и логических проверок вместо использования скобок

Я думаю, что к настоящему времени известно, что &и |может использоваться вместо &&и ||в логических проверках Java (логических). В некоторых случаях вы все равно хотите использовать &&вместо того, &чтобы предотвратить ошибки, как, например index >= 0 && array[index].doSomething. Если значение &&будет изменено на &здесь, он все равно будет оценивать ту часть, где он использует индекс в массиве, вызывая ArrayIndexOutOfBoundsException, следовательно, использование &&в этом случае вместо& .

Пока что основы &&/ ||vs &/| в Java.

Когда вы хотите проверить (A or B) and C, может показаться, что самые короткие используют побитовые операторы:

(A|B)&C    // 7 bytes

Однако, поскольку побитовые операторы имеют приоритет операторов над логическими проверками, вы можете объединить оба, чтобы сохранить байт здесь:

A|B&&C     // 6 bytes

Используйте n+=...-nвместо(long)...

Если у вас есть длинная длина и в лямбда-выходе, например, при использовании Math.pow, вы можете сохранить байт, используя n+=...-nвместо (long)....
Например:

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

Это спасло байты в этом ответе шахты , и даже два байта, комбинируя -n-1в +~nв этом ответе шахты .


В более общем плане для вашего последнего момента вы можете получить доступ / вызвать статические члены из нестатического контекста, такого как экземпляр объекта.
Пок

1
Я не понимаю твоего потолка. Почему вы хотите потолок positive integers? Кроме того , я не уверен , что если реализация CEIL работает .
Джонатан Фрех

1
since Java automatically floors on integers; Я думаю, что правильный термин - усечение , а не настил .
Джонатан Фрех

1
Другая стратегия ПалиндромаString t="";for(int i=s.length();--i>=0;t+=s.charAt(i));return s.equals(t);
Роберто Грэм

1
@RobertoGraham Я на самом деле скопировал свой оригинальный код из неправильного вызова .. Просто s.equals(new StringBuffer(s).reverse()+"")достаточно.
Кевин Круйссен

11

Для игры в гольф, которая не требует ввода, вы можете использовать статические блоки и запускать их без каких-либо основных методов, просто скомпилируйте их с помощью Java 6.

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

1
Вы пытались скомпилировать и запустить его? Этот блок запускается, когда класс загружается загрузчиком классов. Но загрузчик классов ничего не загрузит, пока не узнает класс с методом main.
Cruncher

@Cruncher Вы можете обойти это самостоятельно, указав javaв командной строке / в файле манифеста, какой класс загружать.
AJMansfield

6
@Cruncher, это работало с Java 6. Java 7 изменила способ работы.
Питер Тейлор

1
Выдает исключение в конце, но это работает! Даже на Java 7
stommestack

2
@JopVernooij Если вы не хотите, чтобы на ваше лицо было наложено исключение, вы можете system.exit (), но вы будете тратить впустую персонажей, ни один вызов для гольфа никогда не попросит вас избегать исключений;)
Fabinout

11

Мы все знаем о побитовом xor (^ ), но это также логический xor.

Так (a||b)&&!(a&&b)просто становитсяa^b .

Теперь мы можем использовать xor.

Кроме того , операторы, |а & также работают , просто помните, что приоритет оператора меняется.


5
Пока вы помните приоритет, вы можете использовать & и |также. Это может быть полезно, если ваши условия уже указаны в скобках или если вы уже работаете с логическими значениями.
Geobits

1
Если вам нужен (намного) более низкий приоритет, вы можете использовать !=вместо ^xor и ==xnor
Cyoce

11

Вам не нужно использовать Character.toLowerCase(char c). Вместо этого используйте (c|32). Вместо Character.toUpperCase(char c)использования (c&~32). Это работает только с буквами ASCII.


c|~32будет иметь тенденцию приводить к -1 ... лучше использовать c-32.
feersum

5
@feersum Это не сработает, если вы захотите сделать заглавными буквами прописные буквы.
TheNumberOne

11

Преобразовать строку в число

Есть несколько способов преобразовать строку в числовое значение:

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

новая азбука :

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

Таким образом, для игры в код лучше использовать конструктор при преобразовании строки в числовое значение.

То же самое относится и к Double ; Float; и Byte.


Это не всегда применимо, когда вы можете повторно использовать уже существующий примитив в качестве объекта.
В качестве примера, скажем, у нас есть следующий код:

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

Вы можете использовать .decodeвместо более короткого конструктора, повторно используя параметр в качестве объекта:

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

Не использовать Random !

В общем, если вам нужны случайные числа, Randomэто ужасный способ сделать это *. Намного лучше использовать Math.random()вместо этого. Чтобы использовать Random, вам нужно сделать это (скажем, нам нужен int):

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

Сравните это с:

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

а также:

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

Первый метод принимает 41+15nсимволы ( nэто количество вызовов). Второе это 25nсимволы, а третье43+7n .

Так что, если вам это нужно только один или два раза, используйте встроенный Math.random()метод. Для трех или более звонков вы сэкономите, используя функцию. Либо один сохраняет символы при первом использовании более Random.


Если вы уже используете Math.random()для double, помните, что в четырех случаях, это все еще экономия, чтобы вытащить его в:

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

Для 33 символов вы будете экономить 10 на каждом вызове r()


Обновить

Если вам нужно целое число и вы хотите сэкономить на разыгрывании, не разыгрывайте его! Java автоматически преобразуется, если вы выполняете операцию вместо присваивания. Для сравнения:

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

* Если вам не нужно сеять PRNG для предсказуемых результатов. Тогда я не вижу большого пути обойти это.


2
Не забывайте, Random#nextGaussianхотя.
Джастин

@Quincunx Правда, математика для получения нормального дистрибутива потеряет все ваши сбережения. Я просто буду ссылаться на это как на исключение, которое подтверждает правило;)
Geobits

Обратите внимание, что (int)(Math.random()*9)имеет очень небольшое смещение по модулю, потому что Math.random()возвращает 2 53 возможных значений, а 2 53 не кратно 9. Вероятность каждого числа находится в пределах 1/9 плюс или минус 5 / (9 * 2 ** 53), ошибка настолько мала, что почти точно равна 1/9.
Kernigh

@kernigh Правильно, я использовал 9в качестве примера, это может быть что угодно. Я относительно уверен, что nextInt()(или любой другой Randomметод) также имеет небольшой уклон, просто из-за того, как работает PRNG в Java.
Geobits

1
Нечто связанное с тем, когда вы хотите случайное логическое значение: вместо new java.util.Random().nextBoolean()вы можете использовать Math.random()<.5.
Кевин Круйссен

7

Я не знаю, считаете ли вы эту «чистую» Java, но обработка позволяет вам создавать программы с минимальной начальной настройкой (выполняется автоматически).

Для вывода на консоль у вас может быть что-то простое:

println("hi"); //done

для графического вывода чуть больше:

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 Отличный ресурс! Я обязательно поиграю с этим.
Роб

Было бы хорошо, если бы я добавил ответы других людей к этому? Или это побеждает цель вики сообщества?
Роб

2
Кстати, вам даже не нужно звонить sizeвообще; по умолчанию будет квадрат 100 на 100 пикселей. В большинстве ОС рамка вокруг нее будет примерно вдвое больше, с квадратом по центру, а остальная часть заполнена содержимым, взятым с рабочего стола.
AJMansfield

1
Для графического вывода, если вам не нужна анимация, вы можете просто написать все за пределами setup()и draw()использовать «статический режим». Вы также можете использовать 6-значные шестнадцатеричные цвета, и интерпретатор изменит их, что иногда окупается ( #FF8000< 255,128,0), и если вы используете оттенки серого, необходимо указать только одно число ( 255< 255,255,255)
quat

7

Сокращение возвращения

Вы можете сократить байты возврата строк байтом с помощью:

return "something";

в

return"something";

И, если вам случится начать выражение return с круглых скобок, вы можете сделать то же самое с ними:

return (1+taxRate)*value;

в

return(1+taxRate)*value;

Я предполагаю, что кавычки считаются круглыми скобками? Я на самом деле понял это через AppleScript, как ни странно, и подумал, что стоит упомянуть.


1
То же относится и к числовым знакам, как return-n;вместо return -n;или return~n;вместо return ~n;. А также сингл вместо двойных кавычек:return'A';
Кевин Круйссен

1
По сути, работает для всего, что не может быть частью идентификатора (то есть не буквенное и не цифровое).
Paŭlo Ebermann

7

Не бойтесь использовать научную нотацию

Если вы имеете дело с удвоениями или числами с плавающей запятой, вы можете использовать научную запись чисел. Таким образом, вместо записи double a=1000вы можете изменить его, double a=1e3чтобы сохранить 1 байт.


7

Попробуйте использовать intвместоboolean

В некоторых случаях я обнаружил, что короче возвращать целочисленное значение из метода, который обычно возвращает логическое значение, аналогично тому, что можно сделать в программах на Си.

Сразу же на int4 байта корочеboolean . Каждый раз, когда вы пишете return 0вместо return 1<0, вы сохраняете дополнительные 2 байта и то же самое для return 1 более return 1>0.

Подводный камень в том, что каждый раз, когда вы хотите использовать возвращаемое значение непосредственно как логическое значение, оно стоит 2 байта (if(p(n)) v. if(p(n)>0)). Это может быть восполнено путем использования логической арифметики. Учитывая придуманный сценарий, где вы хотите написать

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

вы можете вместо этого написать

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

чтобы сохранить 2 байта.


6
Я делаю это довольно часто , когда игра в гольф, но имейте в виду , что общий консенсус в том , что 0и 1не являются ложными / верно в Java (и JLS не считает их таким образом либо). Так что, если гольф специально запрашивает правдивость / ложность, вам нужно логизировать его (и, к сожалению, сделать его booleanфункцией, добавив в него еще больше байтов).
Geobits

2
t[0]+=p(n):10?0;Это даже верно?
дорукайхан

@dorukayhan нет, это должно быть t[0]+=p(n)?10:0;. (Я редактировал это.)
Paŭlo Ebermann

6

Если вы используете enum вместо class , вы сохраняете один символ.

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

    }
}

Но вы должны ввести хотя бы один экземпляр enum (в этом примере F, G, H), который должен окупаться самостоятельно.


2
Кажется, вам не нужны никакие экземпляры enum. Я сделал enum M{;public static void main(String[]a){...}без проблем.
Дэнни

3
@ Дэнни Но тогда это не спасет никаких символов. class M{точно такой же длины, как enum M{;. В этом случае я бы пошел с, classпотому что это красивее (IMO)
Джастин

1
по крайней мере, для меня enum{работал без ;после; только IDE стонет, что есть ошибка, но компилятор принимает ее
masterX244

@ masterX244 Какой компилятор / версия? Мой бросает истерику и не будет этого делать.
Geobits

работал на java 1.7 для меня (появился s, для дальнейшего изучения причины с обновлением до .8 он перестал работать)
masterX244

5

Когда у вас есть метод, который должен вернуть booleanили Boolean, то есть:

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

Вы можете изменить тип boolean/ Booleanreturn для Objectсохранения 1 байта:

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

Кроме того, как вы могли заметить, вы можете использовать <1проверку вместо ==0сохранения байта. Хотя это скорее общий совет по коду, а не по Java.
Это в основном используется, когда целое число не может быть отрицательным, например, проверка длины:

a.length<1

вместо

a.length==0

1
Хороший совет! Вы можете добавить другой пример в раздел «если это не может быть отрицательным», чтобы проиллюстрировать это, так как c(-21)возвращается trueс текущим.
Geobits

Уточнено. Кроме того, вы не имеете в виду c(-20)вместо -21? -21 % 5 = 4и -20 % 5 = 0.
Кевин Круйссен

1
Нет, я имел в виду -21. -21 % 5 != 4в Java, что моя точка зрения. Функция, делимая на пять, будет работать правильно, если модуль всегда возвращает неотрицательное значение, но это не так. Смотрите этот пример фрагмента .
Geobits

@ Geobits Ах, спасибо за пример. Я почти никогда не использую отрицательные числа с %, поэтому я забыл, что Java возвращает остаток вместо модуля, отсюда и разница ..
Кевин Круйссен

5

Как рисовать на Java ...

Вот кратчайшая из возможных графических карт краски GUI:

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

Гольф для 111 байтов:

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

5

Избегайте StringBuilderS

Добавление материала к a Stringзанимает гораздо меньше байтов.

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

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

Если вам нужно перевернуть строку и сразу же напечатать ее, используйте 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

Если вам нужно перевернуть строку и затем сделать что-то еще, кроме ее печати, используйте forкаждый цикл.

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

3
Цикл foreach короче, чем StringBufferдля реверсивных строк.String b="";for(char c:"Hello, World!".toCharArray()){b=c+b;}
Тыкать

1
Вам также следует удалить {}из этого цикла foreach, если вы собираетесь использовать этот метод.
Geobits

1
Сохраните 2 байта, используя String s:"".split("")вместо char c:"".toCharArray().
Чарли

Если вы java.util.stream.Streamуже импортировали, и если вам нужно связать другой вызов с результатом (например B.chartAt(42)), или если вам просто нужно передать результат в функцию (например f(B)), то используйтеfor(:) равно для Stream.of("Hello, World!".split("")).reduce("",(a,b)->b+a).
Чарли

Обе линии в вашем примере с for-each можно сыграть в гольф. Первый может стать: String b=new StringBuffer("Hello, World!").reverse()+"";( .toStringзаменяется на +""), а вторая строка может стать: String B="";for(String c:"Hello, World!".split(""))B=c+B;(char к Stringи .toCharArray()к .split("")).
Кевин Круйссен,

5

Используйте Java 10 var

Если вы определяете одну переменную определенного типа, используйте var.

Примеры

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

Не применимо ни в одном из следующих примеров

var не может использоваться во многих примерах

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, почему это не работает со ссылками на методы, обратите внимание, что существуют стандартные функциональные интерфейсы только для небольшого набора сигнатур (и методы могут выдавать проверенные исключения).
Якоб


4

В большинстве случаев ваша программа будет однопоточной, то есть будет работать только один поток. Вы можете использовать этот факт, returnиспользуя метод main, когда вам нужно выйти немедленно.

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

Сравните это с «правильным» завершением программы:

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

Или указывая на null:

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

Или делим на 0:

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

4

Иногда один оператор цикла for можно заменить. Рассмотрим следующий код:

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

Это простой цикл, который является решением этого вопроса .

Поскольку мы знаем, что iон не будет достаточно большим, чтобы вызвать ошибки StackOverflow, мы можем вместо этого заменить цикл for на рекурсию:

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

Мы можем смоделировать цикл, используя троичный оператор в операторе return, чтобы вызвать рекурсию.

Это сокращение довольно специфично, но я могу представить больше ситуаций, когда это пригодится.


4

С помощью ... (varags) в качестве параметра

В некоторых случаях короче использовать Java varargs в качестве параметра вместо свободных.
Например:

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

Большинство будет играть в гольф на это:

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

Но можно прибавить к этому дополнительный байт:

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

Обратите внимание, что все три целых числа доступны только один раз в самом методе. Поскольку intон довольно короткий, полезно только, если вы используете их каждый раз только один раз внутри метода, и в качестве параметра у них есть три или более из них.

С более длинными параметрами это обычно более полезно, хотя. Например, это был мой первоначальный ответ на этот вопрос (рассчитать вхождения входного символа во входную строку):

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

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

И мне порекомендовали сыграть в гольф именно так:

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

Но я закончил этим с помощью ...:

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

ПРИМЕЧАНИЕ. Если вопрос / задача требует гибкого ввода, ...его, []конечно , можно сократить . Если вопрос / задача специально запрашивает, скажем, три Stringввода и запрещает Stringмассив, содержащий три значения, вы можете использовать String...вместо String a,String b,String c.


2
Разве вы не можете использовать String[]вместо varargs? (сохраняет еще 1 байт)
Kritixi Lithos

@KritixiLithos Хм .. хорошая мысль. Но это в основном зависит от того, насколько гибкий ввод для решения проблемы. Если разрешен какой-либо формат ввода, он будет короче. Я добавлю это к этим советам, спасибо.
Кевин Круйссен,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.