Java打高尔夫球技巧


86

在Java中是否可以使用任何有用的快捷方式?

如下所示,import已经在程序中添加了至少17个字符。

import java.io.*;

我知道简单的解决方案是使用另一种语言,但是缩短Java程序似乎是一个真正的挑战。


提示应特定于Java:如果它们适用于大多数类似C的语言,则它们属于更一般的提示列表


9
package可以跳过。
st0le 2012年

在回答中,我不能仅假设进口就在这里就忽略它们吗?
Fabricio 2014年

1
@Fabricio除非OP如此指定,否则不会。
nyuszika7h 2014年

32
关于高尔夫Java的最佳提示:不要使用它。;)
kirbyfan64sos 2015年

4
“我想在Java中打高尔夫球”祝您好运
sagiksp

Answers:


85
  • 使用最新的Java。Java 8允许您使用lambda表达式,因此,即使您需要诸如函数对象之类的东西,也可以使用它。

  • 为您经常使用的东西定义缩短的功能。例如,您有100个调用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);

  • 使用内联分配,增量,实例化。在适当的地方使用匿名内联类。如果可能,请改用lambda。嵌套函数调用。某些函数可以保证返回其父对象,而实际上这些函数甚至意味着要链接在一起。

  • 您的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();method,而是追加append someTypeValue+""

  • 如果确实需要Windows,请不要使用Swing,而应使用AWT(除非您确实需要Swing中的功能)。比较import javax.swing.*;import java.awt.*;。此外,在Swing组件都有一个J前缀,以他们的名字(JFrameJLabel,等),但在AWT组件不(FrameLabel,等)


43

使用interface代替class

在Java 8中,将静态方法添加到接口。在接口中,默认情况下所有方法都是公共的。所以

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

现在可以缩短为

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

这显然更短。

例如,在“ Hello,World!”中使用了此功能挑战。


8
我不知道!+1,
妙招

是的,减少样板!
CalculatorFeline

3
我必须部分不同意(也使用这种技术,在“ Hello,World!”挑战赛中击败了您)。
奥利维尔·格雷戈尔

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.*
Johannes Kuhn

1
我知道这是一个古老的答案,但是在Java 10中,您现在可以做到var o=System.out;这一点,只需要使用两次就可以了
Luke Stevens

@LukeStevens:好吧,也许您发现了Java10可能进行的其他改进,并且围绕Java10形成了单独的答案?
用户未知

1
@LukeStevens可以var o=System.out.println工作吗?
MilkyWay90

25

main不必调用to的参数args,您可以削减一些空格:

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

会很好的。


1
如果未明确指出编写完整程序,答案是否需要包含main函数?我一直在使用lambda表达式作为答案。
Makotosan

3
@Makotosan不,他们没有;Lambda通常很好。
daniero

21

如果必须使用布尔表达式truefalse,请分别用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 2014年

24
@Geobits:boolean t=1>0,f=!t;-缩短一个字符!
bobbel 2014年

6
这个例子不是很好。在这种情况下,您可以避免直接使用true/ 以及其他许多(!)falsef|=a[i++]==42;节省很多。
IngoBürk2014年

@IngoBürk是。在撰写本文时,我主要考虑的是使用的库函数boolean,但是由于在撰写本文时无法提供任何示例(我通常不使用Java代码),所以我只写了一个简单的示例。
ace_HongKong独立2014年

1
@Geobits对Java不太熟悉,但是您可以只定义1并使用t和!t(再次我不知道Java,只是好奇)
Albert Renshaw 2015年

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

这几乎肯定会触发有关“从变量访问静态方法”的思想警告。


((Integer)1).parseInt("1")也可以。
魔术八达通Ur

5
@carusocomputing new Integer("1")甚至更短。但是贾斯汀对他的回答的意思是,您可以将已经拥有的变量重用于静态调用。正如我在此答案底部所解释的。
Kevin Cruijssen

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>>>1Integer.MIN_VALUE(-2147483648)写得更好1<<31


14

如果您需要从参数(或任何其他字符串)中获取数字,通常会看到类似以下内容的内容:

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

很多时候,你并不需要Integer。很多挑战不会大量使用。由于ShortByte都将取消装箱到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 2014年

14

不要使用public class。main方法需要是公共的,但它的类不需要。此代码有效:

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

java S即使class S不是公开课,您也可以参加比赛。(更新:撰写本文时,我正在使用Java7。在Java 8中,您的主要方法应该在接口中。在Java 5或6中,您的主要方法应该在枚举中。)

很多Java程序员都不知道这一点!关于非公共类中的main 的Stack Overflow问题的大约一半答案错误地声称main方法必须在公共类中。现在您知道了。删除publicin public class并保存7个字符。


1
除非您针对1.8之前的Java,否则构造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.nioAPI中使用的规范名称,以及java.iojava.langAPI中使用的规范名称。这是Java中所有受支持的编码的完整列表。因此,请始终使用两者中最短的一个。第二个通常较短(如UTF-8vs utf8Windows-1252vs Cp1252等),但并不总是较短(UTF-16BEvs 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:

如果您要使用双精度数/浮点数并且想要使用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的包含静态字段ZEROONETEN。因此,当您仅使用这三个时,就不需要使用,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                  

注意:您必须使用=nullso t进行初始化才能使用t.

有时,您可以添加多个BigIntegers来创建另一个以节省字节。因此,假设您1,10,12出于某种原因希望拥有BigIntegers :

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

在打印字符或将其附加到字符串或类似内容时,循环遍历字符可能很有用。

但是,如果你只使用一些Unicode的数量计算的字符,你可以替换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将返回“ 此字符串的副本,其中删除了前导和尾随空白,如果没有前导或尾随空白则返回此字符串 ”在有人向我建议之后,在我的这个答案中,我使用了它

回文:

要检查一个字符串是否是回文(记住字符串的偶数和奇数长度),这是最短的(.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

而且,如果要检查两个ab是否均为零,则可以使用按位或,或者如果它们始终为正,则将它们加在一起:

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(Exception 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,n)

当您想要2的幂时,按位计算的方法要短得多:

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

结合按位和逻辑检查,而不使用括号

我认为这是现在众所周知的&,并|可以用来代替&&||中爪哇(布尔)逻辑检查。在某些情况下,您仍然想使用&&而不是&防止错误,例如index >= 0 && array[index].doSomething。如果&&将更改为&此处,它将仍然评估在数组中使用索引的部分,从而导致ArrayIndexOutOfBoundsException,因此&&在这种情况下使用代替&

到目前为止,Java 中&&/ ||vs &/ 的基础知识|

当您想检查时(A or B) and C,最短的似乎使用了如下的按位运算符:

(A|B)&C    // 7 bytes

但是,由于按位运算符的优先级高于逻辑检查,因此您可以将两者合并以在此处保存一个字节:

A|B&&C     // 6 bytes

使用n+=...-n代替(long)...

例如,当使用lambda时,输入和输出中都有一个长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 2013年

@Cruncher您可以通过java在命令行/清单文件中告诉要加载的类来解决此问题。
AJMansfield

6
@Cruncher,它与Java 6一起使用。Java7改变了它的工作方式。
彼得·泰勒

1
最后抛出异常,但是它可以工作!即使是在Java 7中
stommestack

2
@JopVernooij如果您不想在自己的脸上抛出异常,可以使用system.exit(),但是您会浪费角色,没有高尔夫挑战赛会要求您避免异常;)
Fabinout 2014年

11

我们都知道按位异或(^),但它也是逻辑异或。

于是(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 2014年

5
@feersum如果您想将大写字母变成大写,那将不起作用。
TheNumberOne 2014年

11

将字符串转换为数字

有多种将String转换为数值的方法:

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

新ABC

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

因此,对于代码查询,最好在将String转换为数值时使用构造函数。

同样适用于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()for 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 2014年

@kernigh对,我9只是作为例子,可以是任何东西。我相对确定nextInt()(或任何其他Random方法)也存在较小的偏差,这仅仅是由于Java的PRNG的工作方式而引起的。
Geobits 2014年

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优秀资源!我一定会玩弄它。
罗布

如果在此答案中添加其他人的答案,那还好吗?还是违反社区维基的目的?
罗布2012年

2
顺便说一句,您甚至根本不必打电话size;它将默认为100 x 100像素的正方形。在大多数操作系统中,其周围的框架大约是框架的两倍,正方形居中,其余区域填充了从桌面获取的内容。
AJMansfield

1
对于图形输出,如果不需要动画,则可以编写所有外部内容setup()draw()使用“静态模式”。您还可以使用6位数的十六进制颜色,解释器将更改它们,有时会有所回报(#FF8000< 255,128,0),如果您使用灰度,则只需指定一个数字(255< 255,255,255
2016年

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';
Kevin Cruijssen

1
基本上,它适用于不能作为标识符一部分的任何事物(即非字母和非数字)。
圣保罗Ebermann

7

不要害怕使用科学计数法

如果要处理双精度数或浮点数,则可以对数字使用科学计数法。因此,无需编写double a=1000即可将其更改double a=1e3为节省1个字节。


7

尝试使用int代替boolean

在某些情况下,我发现从通常会返回布尔值的方法中返回整数值要短一些,这与在C程序中执行的操作类似。

蝙蝠马上int比短4个字节boolean。每次写入return 0而不是写入时return 1<0,都将额外保存2个字节,并且在return 1 over处保持相同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,2015年

2
t[0]+=p(n):10?0;这甚至有效吗?
dorukayhan

@dorukayhan不,它的意思是t[0]+=p(n)?10:0;。(我对其进行了编辑。)
PaŭloEbermann,

6

如果使用enum而不是class,则保存一个字符。

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

    }
}

但是您必须引入至少一个枚举实例(在此示例中为F,G,H),这些实例必须自己偿还。


2
似乎您不需要任何枚举实例。我enum M{;public static void main(String[]a){...}没有问题。
丹尼

3
@Danny但是它不会保存任何字符。class M{与的长度完全相同enum M{;。在那种情况下,我会选择class因为它更漂亮(IMO)
贾斯汀

1
至少对我而言,enum{工作没有;时间;它唯一的IDE抱怨有错误,但编译器接受它
masterX244 2014年

@ masterX244什么编译器/版本?我的发脾气,不会这样做。
Geobits

为我工作过Java 1.7(出现s,需要进一步调查原因,将其更新为.8使其停止工作)
masterX244 2014年

5

当您具有应返回boolean或的方法时Boolean,即:

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

您可以将boolean/ Booleanreturn-type更改Object为保存1个字节:

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

另外,您可能已经注意到,可以使用<1检查而不是==0保存字节。尽管这是通用的代码技巧,而不是特定于Java的技巧。
这通常在整数不能为负数时使用,例如检查长度:

a.length<1

代替

a.length==0

1
不错的提示!您可能想在“如果不能为负数”部分中添加另一个示例进行说明,因为它与当前示例一起c(-21)返回true
Geobits,2016年

澄清。另外,您c(-20)不是要代替-21吗?-21 % 5 = 4-20 % 5 = 0
凯文·克鲁伊森

1
不,我是说-21-21 % 5 != 4在Java中,这就是我的观点。如果模数始终返回非负数,则可被5整除的函数正常工作,但不是。参见此示例片段
Geobits,2016年

@Geobits啊,谢谢你的例子。我几乎从来不使用负数%,所以我忘了的Java返回余数,而不是模量,因此..区别
凯文Cruijssen

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

将内容附加到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

如果您必须反转字符串然后执行除打印字符串以外的其他操作,请使用foreach循环。

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
使用String s:"".split("")代替节省2个字节char c:"".toCharArray()
查理

如果您java.util.stream.Stream已经导入,并且需要将另一个调用链接到结果(如B.chartAt(42)),或者只需要将结果传递给函数(如f(B)),则使用for(:)equall即可Stream.of("Hello, World!".split("")).reduce("",(a,b)->b+a)
查理

您的示例中带有for-for的两条线都可以打高尔夫球。第一个可以成为:String b=new StringBuffer("Hello, World!").reverse()+"";.toString替换为+""),和您的第二线可以变成:String B="";for(String c:"Hello, World!".split(""))B=c+B;charString.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)

关于为什么这不适用于方法引用,请注意,仅少数签名具有标准功能接口(方法可以引发检查的异常)。
雅各布


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

这是一个简单的for循环,可以解决这个问题

因为我们知道那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包含三个值的-array,则可以使用String...代替String a,String b,String c


2
您不能使用a String[]而不是使用varargs吗?(再节省1个字节)
奶牛嘎嘎叫声

@KritixiLithos嗯..好点。但这主要取决于输入对挑战的灵活性。如果允许任何输入格式,那确实会更短。谢谢,我会将其添加到此提示中。
凯文·克鲁伊森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.