เคล็ดลับการตีกอล์ฟในจาวา


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 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)นั้นแตกต่างกัน) งบเพิ่มเติมควรจะอยู่ภายในคำสั่งตัวเองเช่นforfor(int i=0;i<m;a(i),b(++i))c(i);

  • ใช้การกำหนดแบบอินไลน์การเพิ่มอินสแตนซ์ ใช้คลาสอินไลน์ที่ไม่ระบุชื่อตามความเหมาะสม ใช้ lambdas แทนถ้าเป็นไปได้ ฟังก์ชั่นการโทร Nest ฟังก์ชั่นบางอย่างรับประกันว่าจะส่งคืนวัตถุแม่ของพวกเขาจริง ๆ แล้วมันหมายถึงการถูกล่ามโซ่ไว้ด้วยกัน

  • mainวิธีการของคุณthrows Exceptionไม่จับพวกเขา

  • ErrorExceptionจะสั้นกว่า หากมีเหตุผลบางอย่างที่คุณจริงๆต้อง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+""

  • หากคุณต้องการ windows อย่าใช้ Swing ใช้ AWT (เว้นแต่คุณต้องการบางอย่างจาก Swing) เปรียบเทียบและimport javax.swing.*; import java.awt.*;นอกจากนี้องค์ประกอบในสวิงมีJใช้ได้กับชื่อของพวกเขา ( JFrame, JLabelฯลฯ ) แต่องค์ประกอบใน AWT ทำไม่ได้ ( Frame, Labelฯลฯ )


43

ใช้แทนinterfaceclass

ใน java 8 มีการเพิ่มเมธอดสแตติกเข้ากับอินเตอร์เฟส ในส่วนต่อประสานวิธีการทั้งหมดเป็นแบบสาธารณะโดยค่าเริ่มต้น ดังนั้น

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

สามารถย่อให้เหลือ

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

ซึ่งสั้นกว่าอย่างเห็นได้ชัด

ตัวอย่างเช่นฉันใช้คุณสมบัตินี้ในHello, World! ท้าทาย.


8
ฉันไม่รู้ว่า! +1, เคล็ดลับดี
HyperNeutrino

เย่น้อยกว่าสำเร็จรูป!
CalculatorFeline

3
ฉันต้องไม่เห็นด้วยบางส่วน (เช่นกันฉันเอาชนะคุณในการท้าทาย "สวัสดีโลก!" โดยใช้เทคนิคนั้น)
Olivier Grégoire

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
โอ้ คุณสามารถทำสิ่งนี้ได้! และตลอดเวลาที่ฉันคิดว่านี่เป็นไปไม่ได้Java!
Justin

12
คุณสามารถใช้งานimport static java.lang.System.*ได้
Johannes Kuhn

1
ฉันรู้ว่านี่เป็นคำตอบเก่า แต่ใน Java 10 ตอนนี้คุณสามารถทำได้var o=System.out;ซึ่งจำเป็นต้องใช้สองครั้งก่อนที่มันจะจ่ายออกไป
ลุคสตีเวนส์

@LukeStevens: บางทีคุณอาจจะพบการปรับปรุงอื่น ๆ ที่เป็นไปได้ด้วย Java10 และสร้างคำตอบแยกต่างหากสำหรับ Java10?
ผู้ใช้ที่ไม่รู้จัก

1
@LukeStevens จะvar o=System.out.printlnใช้ได้ไหม
MilkyWay90

25

อาร์กิวเมนต์ที่mainไม่จำเป็นต้องมีการเรียกใช้argsและคุณสามารถตัดช่องว่างบางส่วน:

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

จะทำอะไรได้ดี


1
คำตอบจำเป็นต้องมีฟังก์ชั่นหลักหรือไม่หากไม่ระบุอย่างชัดเจนให้เขียนโปรแกรมเต็มรูปแบบ? ฉันใช้คำแลมบ์ดาเป็นคำตอบ
Makotosan

3
@Makotosan ไม่มีพวกเขาทำไม่ได้; แลมบ์ดานั้นปกติแล้ว
daniero

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;- ถ่านหนึ่งตัวสั้นลง!
bobbel

6
ตัวอย่างไม่ดีจริงๆ ในกรณีนี้และอื่น ๆ อีกมากมาย (!) คุณสามารถหลีกเลี่ยงการใช้true/ falseโดยตรงได้: f|=a[i++]==42;บันทึกได้ค่อนข้างมาก
Ingo Bürk

@ IngoBürk True เมื่อฉันเขียนสิ่งนี้ฉันมักจะคิดถึงฟังก์ชั่นห้องสมุดที่ใช้booleanแต่เนื่องจากฉันไม่สามารถหาตัวอย่างในเวลาที่ทำการเขียนได้ (ฉันมักจะไม่ใช้โค้ดใน Java) ฉันเพิ่งเขียนตัวอย่างง่ายๆ
ace_HongKong การพึ่งพา

1
@Geobits ไม่คุ้นเคยกับจาวา แต่คุณสามารถกำหนด 1 และใช้ t และ! t (อีกครั้งฉันไม่รู้ Java, อยากรู้อยากเห็น)
Albert Renshaw

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")ทำงานเกินไป
Magic Octopus Urn

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>>>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ในกรณีส่วนใหญ่
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 วิธีหลักของคุณควรอยู่ใน enum )

โปรแกรมเมอร์ Java จำนวนมากไม่รู้สิ่งนี้! ประมาณครึ่งคำตอบสำหรับคำถาม Stack Overflow เกี่ยวกับ main ในคลาสที่ไม่ใช่แบบสาธารณะอ้างอย่างผิด ๆ ว่าวิธีหลักต้องอยู่ใน public class ตอนนี้คุณรู้ดีขึ้นแล้ว ลบpublicในpublic classและบันทึก 7 ตัว


1
เว้นแต่ว่าคุณกำลังกำหนดเป้าหมาย Java ก่อนหน้า 1.8 การสร้างinterface s{static void main(String[]...จะสั้นกว่า หากคุณต้องมีไฟล์ต้นฉบับที่คอมไพล์ได้และวิธีการหลัก เนื่องจากในอินเตอร์เฟส Java 1.8 วิธีการทั้งหมดเป็นแบบสาธารณะดังนั้นคุณสามารถข้ามโมดิฟายเออร์บนวิธีการได้
Douglas จัดขึ้น

ฉันไม่ได้ใช้ Java เมื่อเร็ว ๆ นี้ดังนั้นคำตอบของฉันจึงล้าสมัย ฉันลืมว่าอินเตอร์เฟสสามารถมีวิธีการใน Java 8
kernigh

ฉันไม่ได้เรียนรู้จากการเขียนโปรแกรม ฉันเรียนรู้มันจากการเล่นกอล์ฟ :)
ดักลาสจัดขึ้น

14

เคล็ดลับการตีกอล์ฟเล็ก ๆ

เคล็ดลับเหล่านี้มีขนาดเล็กเกินไปสำหรับคำตอบที่แยกดังนั้นฉันจะใช้คำตอบนี้สำหรับเคล็ดลับ codegolfing ขนาดเล็กมากที่ฉันพบหรือเกิดขึ้นและยังไม่ได้กล่าวถึงในเคล็ดลับอื่น ๆ :

การลบอักขระตัวสุดท้ายของสตริง:

// 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.ioและjava.langAPI นี่คือรายการทั้งหมดของการเข้ารหัสที่รองรับใน Java ดังนั้นควรใช้เวลาที่สั้นที่สุดของทั้งสอง ที่สองมักจะสั้นกว่า (เช่นUTF-8vs utf8, Windows-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 ประกอบด้วยเขตข้อมูลแบบคงที่สำหรับ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เพื่อจะเริ่มต้นในการใช้tt.

บางครั้งคุณสามารถเพิ่ม 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

การวนรอบตัวอักขระอาจมีประโยชน์เมื่อพิมพ์ออกมาหรือผนวกเข้ากับสตริงหรือสิ่งที่คล้ายกัน

อย่างไรก็ตามหากคุณใช้ตัวอักษรสำหรับการคำนวณตัวเลขแบบ 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จะกลับมา " สำเนาของสายนี้ที่มีชั้นนำและลากพื้นที่สีขาวลบหรือสายนี้ถ้ามันไม่เคยมีใครนำหน้าหรือต่อท้ายพื้นที่สีขาว . " ผมเคยใช้นี้หลังจากที่มีคนแนะนำนี้กับผมในคำตอบของฉันนี้

ประโยค:

ในการตรวจสอบว่า String เป็น palindrome หรือไม่ (คำนึงถึงความยาวของ Strings ทั้งคู่และคี่) นี่เป็นระยะสั้นที่สุด ( .containsทำงานที่นี่เพราะเรารู้ว่าทั้ง String เองและรูปแบบที่ตรงกันข้ามนั้นมีความยาวเท่ากัน):

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เป็นศูนย์คุณสามารถใช้บิต - OR หรือเพิ่มเข้าด้วยกันหากพวกเขาเป็นบวกเสมอ:

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ในความคิดเห็นนี้

ลองในที่สุดแทนที่จะลองจับ (ข้อยกเว้น e) เมื่อกลับมาและเมื่อจะใช้

หากคุณไม่สามารถใช้ a throws Exceptionได้ แต่ต้องcatchทำบางสิ่งบางอย่างด้วยมันก่อนส่งคืนคุณสามารถใช้finallyแทน:

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

สำหรับตัวอย่างของการใช้ a try-catchฉันสามารถอ้างถึงคำตอบของฉัน (เครดิตสำหรับการเล่นกอล์ฟทางอ้อมไปที่@KamilDrakari ) ในความท้าทายนี้เราต้องห่วงแนวทแยงมุมกว่าเมทริกซ์ NxM ดังนั้นเราจึงมีการตรวจสอบว่าจำนวนของคอลัมน์หรือจำนวนแถวที่เป็นที่ต่ำที่สุดเท่าที่สูงสุดของเราในสำหรับวง (ซึ่งเป็นราคาแพงมากในแง่ของไบต์: 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 bytes) finallyจริงเพิ่มขึ้นนับไบต์แทนการลดลงถ้าฉันจะได้ใช้

Math.pow (2, n)

เมื่อคุณต้องการพลัง 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สั้นที่สุดอาจใช้ตัวดำเนินการ bit-wise ดังนี้:

(A|B)&C    // 7 bytes

อย่างไรก็ตามเนื่องจากตัวดำเนินการ bit-wise มีตัวดำเนินการที่สำคัญเหนือกว่าการตรวจสอบแบบลอจิคัลคุณสามารถรวมทั้งสองเพื่อบันทึกไบต์ที่นี่:

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ในคำตอบของฉันนี้


โดยทั่วไปสำหรับจุดสุดท้ายของคุณคุณสามารถเข้าถึง / เรียกใช้สมาชิกแบบคงที่จากบริบทที่ไม่คงที่เช่นอินสแตนซ์ของวัตถุ
Poke

1
ฉันไม่เข้าใจเคล็ดลับเพดานของคุณ ทำไมคุณถึงต้องการเพดานpositive integers? นอกจากนี้ฉันไม่แน่ใจว่าการใช้งานบนเพดานนั้นใช้งานได้หรือไม่
Jonathan Frech

1
since Java automatically floors on integers; ผมคิดว่าในระยะที่เหมาะสมคือการตัดไม่พื้น
Jonathan Frech

1
กลยุทธ์ Palindrome อื่นString t="";for(int i=s.length();--i>=0;t+=s.charAt(i));return s.equals(t);
Roberto Graham

1
@ RobertoGraham ฉันคัดลอกโค้ดดั้งเดิมของฉันจากความท้าทายที่ผิด .. แค่s.equals(new StringBuffer(s).reverse()+"")พอแล้ว
Kevin Cruijssen

11

สำหรับการตีกอล์ฟที่ไม่ต้องการอินพุตคุณสามารถใช้บล็อกแบบคงที่และรันได้โดยไม่ต้องใช้วิธีการหลักใด ๆ เพียงแค่คอมไพล์ด้วย Java 6

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

1
คุณพยายามคอมไพล์และรันหรือไม่? บล็อกนี้จะทำงานเมื่อชั้นได้รับการโหลดโดย class loader แต่ตัวโหลดคลาสจะไม่โหลดสิ่งใดจนกว่ามันจะรู้จักคลาสด้วยเมธอดหลัก
Cruncher

@ Cruncher คุณสามารถแก้ไขได้ด้วยตัวเองjavaในบรรทัดคำสั่ง / ในไฟล์ Manifest เพื่อโหลดคลาส
AJMansfield

6
@Cruncher ซึ่งทำงานกับ Java 6 Java 7 เปลี่ยนวิธีการทำงาน
Peter Taylor

1
โยนข้อยกเว้นในตอนท้าย แต่มันใช้งานได้! แม้แต่ใน Java 7
stommestack

2
@JopVernooij หากคุณไม่ต้องการมีข้อยกเว้นที่ถูกส่งไปที่ใบหน้าของคุณคุณสามารถ system.exit () แต่คุณจะเสียตัวละครไม่ท้าทายกอล์ฟเคยขอให้คุณหลีกเลี่ยงข้อยกเว้น;
# Fabinout

11

เราทุกคนรู้เกี่ยวกับ bitwise 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

ใหม่ ABC :

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

ดังนั้นสำหรับ code-golfing วิธีที่ดีที่สุดคือใช้ตัวสร้างเมื่อแปลงสตริงเป็นค่าตัวเลข

เช่นเดียวกับ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แทน constructor ที่สั้นกว่าโดยใช้พารามิเตอร์เป็น object อีกครั้ง:

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คือจำนวนการโทร) ประการที่สองคือตัวละครและคนที่สามคือ25n43+7n

ดังนั้นหากคุณต้องการเพียงครั้งเดียวหรือสองครั้งให้ใช้Math.random()วิธีการแบบอินไลน์ สำหรับการโทรสามครั้งขึ้นไปคุณจะประหยัดได้โดยใช้ฟังก์ชั่น คนใดคนหนึ่งจะช่วยประหยัดตัวอักษรในการใช้ครั้งแรกRandomมากกว่า


หากคุณกำลังใช้Math.random()สำหรับdoubleจำไว้ว่าที่สี่การใช้งานก็ยังคงเป็นเงินฝากออมทรัพย์ที่จะดึงมันออกไป:

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

สำหรับ 33 ตัวอักษรคุณจะประหยัดได้ 10 สายต่อการโทรแต่ละครั้ง r()


ปรับปรุง

หากคุณต้องการจำนวนเต็มและต้องการประหยัดในการคัดเลือกนักแสดงอย่าใช้เลย! Java auto-casts หากคุณทำการดำเนินการแทนการมอบหมาย เปรียบเทียบ:

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

* ยกเว้นกรณีที่คุณต้องเริ่มต้นใช้งาน PRNG เพื่อให้ได้ผลลัพธ์ที่คาดการณ์ได้ จากนั้นฉันไม่เห็นทางรอบ ๆ


2
อย่าลืมRandom#nextGaussianว่า
จัสติน

@Quincunx True การทำคณิตศาสตร์เพื่อให้ได้การแจกแจงแบบปกติที่ดีจะทำให้คุณประหยัดเงินได้ ฉันจะอ้างถึงสิ่งนั้นเป็นข้อยกเว้นที่พิสูจน์กฎ;)
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
Kevin Cruijssen

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 สุดยอดแหล่งข้อมูล! ฉันจะแน่ใจว่าได้เล่นกับมัน
Rob

มันจะไม่เป็นไรถ้าฉันเพิ่มคำตอบของคนอื่นในนี้? หรือว่าเอาชนะวัตถุประสงค์ของวิกิชุมชนหรือไม่
Rob

2
โดยวิธีการที่คุณไม่ต้องโทรsizeเลย มันจะเริ่มต้นที่สี่เหลี่ยมจัตุรัส 100 ถึง 100 พิกเซล ในระบบปฏิบัติการส่วนใหญ่เฟรมรอบ ๆ จะมีขนาดใหญ่เป็นสองเท่าโดยมีสี่เหลี่ยมอยู่กึ่งกลางและพื้นที่ส่วนที่เหลือเต็มไปด้วยเนื้อหาที่นำมาจากเดสก์ท็อป
AJMansfield

1
สำหรับเอาต์พุตกราฟิกหากคุณไม่ต้องการภาพเคลื่อนไหวคุณสามารถเขียนทุกอย่างภายนอกsetup()และdraw()ใช้ "โหมดคงที่" นอกจากนี้คุณยังสามารถใช้สีหกเหลี่ยม 6 หลักและล่ามจะเปลี่ยนซึ่งบางครั้งก็จ่ายออก ( #FF8000< 255,128,0) และหากคุณใช้ greyscale ต้องมีการระบุหมายเลขหนึ่ง ( 255< 255,255,255)
quat

7

ร่นกลับ

คุณสามารถย่อคำสั่ง return ของสตริงให้สั้นลงด้วยไบต์ด้วย:

return "something";

ไปยัง

return"something";

และหากคุณเริ่มต้นข้อความสั่งการส่งคืนด้วยวงเล็บคุณสามารถทำสิ่งเดียวกันกับพวกเขาได้:

return (1+taxRate)*value;

ไปยัง

return(1+taxRate)*value;

ฉันเดาว่าคำพูดนั้นถือว่าเป็นเครื่องหมายวงเล็บหรือไม่? จริง ๆ แล้วฉันหยิบมันขึ้นมาจาก AppleScript สนุกพอและคิดว่ามันน่าจะพูดถึง


1
เช่นเดียวกับสัญญาณจำนวนเช่นreturn-n;แทนreturn -n;หรือแทนreturn~n; return ~n;เช่นเดียวกับคำพูดเดียวแทนที่จะเป็นคำพูดสองคำ:return'A';
Kevin Cruijssen

1
โดยพื้นฐานแล้วทำงานเพื่อสิ่งใดก็ตามที่ไม่สามารถเป็นส่วนหนึ่งของตัวระบุได้ (เช่นไม่ใช่ตัวอักษรและไม่ใช่ตัวเลข)
Paŭlo Ebermann

7

อย่ากลัวที่จะใช้สัญลักษณ์ทางวิทยาศาสตร์

หากคุณกำลังติดต่อกับคู่หรือลอยคุณสามารถใช้สัญลักษณ์ทางวิทยาศาสตร์สำหรับตัวเลข ดังนั้นแทนที่จะเขียนdouble a=1000คุณสามารถเปลี่ยนเป็นdouble a=1e3บันทึก 1 ไบต์


7

ลองใช้intแทนboolean

ในบางกรณีฉันพบว่ามันสั้นกว่าที่จะคืนค่าจำนวนเต็มจากวิธีที่ตามปกติแล้วจะส่งคืนบูลีนคล้ายกับสิ่งที่อาจทำในโปรแกรม C

ขวาปิดค้างคาวintเป็น 4 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

@dorukayhan t[0]+=p(n)?10:0;ไม่มันหมายถึงการเป็น (ฉันแก้ไขมัน)
Paŭlo Ebermann

6

ถ้าคุณใช้enum แทนคลาสคุณจะบันทึกอักขระหนึ่งตัว

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){...}โดยไม่มีปัญหา
Danny

3
@ แดนนี่ แต่แล้วมันก็ไม่ได้บันทึกอักขระใด ๆ ตรงยาวเช่นเดียวกับclass M{ enum M{;ในกรณีนั้นฉันจะไปด้วยclassเพราะมันสวยกว่า (IMO)
จัสติน

1
อย่างน้อยสำหรับฉันenum{ทำงานโดยไม่ต้อง;หลังจากนั้น มันเป็นเพียง IDE ครวญครางว่ามีข้อผิดพลาด แต่คอมไพเลอร์ยอมรับมัน
masterX244

@ masterX244 คอมไพเลอร์ / รุ่นใด? ฉันโยนความโกรธเคืองและไม่ทำมัน
Geobits

ทำงานบน java 1.7 สำหรับฉัน (ปรากฏ s, ned เพื่อตรวจสอบสาเหตุเพิ่มเติมด้วยการอัปเดตเป็น. 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-type Objectเป็น Save 1 byte:

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

นอกจากนี้ตามที่คุณอาจสังเกตเห็นคุณสามารถใช้การ<1ตรวจสอบแทน==0การบันทึกไบต์ แม้ว่าจะเป็นคำแนะนำทั่วไปเกี่ยวกับกอล์ฟแทนที่จะเป็นจาวาเฉพาะ
ส่วนใหญ่จะใช้เมื่อจำนวนเต็มไม่สามารถลบได้เช่นตรวจสอบความยาว:

a.length<1

แทน

a.length==0

1
คำแนะนำที่ดี! คุณอาจต้องการเพิ่มอีกตัวอย่างในส่วน "หากไม่สามารถเป็นลบ" เพื่อแสดงให้เห็นเนื่องจากc(-21)กลับมาtrueด้วยตัวอย่างปัจจุบัน
Geobits

ชี้แจง นอกจากนี้คุณไม่ได้หมายถึงc(-20)แทนที่จะ-21? และ-21 % 5 = 4 -20 % 5 = 0
Kevin Cruijssen

1
-21ไม่ฉันหมายถึง -21 % 5 != 4ใน Java ซึ่งเป็นจุดของฉัน การหารด้วยห้าฟังก์ชันจะทำงานได้อย่างถูกต้องหากโมดูลัสคืนค่าที่ไม่เป็นลบเสมอ แต่จะไม่ทำงาน ดูตัวอย่างข้อมูลตัวอย่างนี้
Geobits

@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();
}

Golfed สำหรับ 111 Bytes:

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

5

หลีกเลี่ยง StringBuilder s

การต่อท้ายข้อมูลลงใน 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 loop นั้นสั้นกว่าStringBufferการย้อนกลับสตริง String b="";for(char c:"Hello, World!".toCharArray()){b=c+b;}
Poke

1
คุณควรลบออก{}จากลูป foreach นั้นถ้าคุณจะใช้วิธีการนั้น
Geobits

1
บันทึก 2 ไบต์ใช้แทนString s:"".split("") char c:"".toCharArray()
charlie

ถ้าคุณได้java.util.stream.Streamนำเข้ามาแล้วและถ้าคุณจำเป็นต้องห่วงโซ่สายอื่นเพื่อผล (ชอบB.chartAt(42)) หรือถ้าคุณเพียงต้องการที่จะผ่านผลให้ฟังก์ชั่น (ชอบf(B)) แล้วใช้for(:)เป็น equall Stream.of("Hello, World!".split("")).reduce("",(a,b)->b+a)ไป
charlie

เส้นทั้งสองในตัวอย่างของคุณพร้อมตัวต่อแต่ละตัวสามารถตีกอล์ฟได้ บรรทัดแรกสามารถกลายเป็น: String b=new StringBuffer("Hello, World!").reverse()+"";( .toStringแทนที่ด้วย+"") และบรรทัดที่สองของคุณสามารถกลายเป็น: String B="";for(String c:"Hello, World!".split(""))B=c+B;( charไปยังStringและ.toCharArray()ไป.split(""))
Kevin Cruijssen

5

ใช้ Java 10's 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 เหตุใดจึงไม่ทำงานกับการอ้างอิงเมธอดโปรดทราบว่ามีอินเทอร์เฟซการทำงานมาตรฐานสำหรับชุดลายเซ็นขนาดเล็กเพียงชุดเดียว
Jakob

หนึ่งโพสต์ StackOverflow ที่เกี่ยวข้องในเรื่องของข้อ จำกัด ของวิธีการอ้างอิง
Jonathan Frech

4

ในกรณีส่วนใหญ่โปรแกรมของคุณจะเป็นแบบเธรดเดียวนั่นคือมันจะมีเธรดเดียวเท่านั้นที่ทำงานอยู่ คุณสามารถใช้ประโยชน์จากข้อเท็จจริงนี้ได้โดยreturnเริ่มจากวิธีการหลักเมื่อคุณต้องออกจากระบบทันที

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-loop เดียวอาจเปลี่ยนได้ พิจารณารหัสต่อไปนี้:

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

นี่คือ for-loop ง่าย ๆ ซึ่งเป็นวิธีแก้ปัญหาสำหรับคำถามนี้

เนื่องจากเรารู้ว่าiจะไม่ใหญ่พอที่จะทำให้เกิดข้อผิดพลาด StackOverflow เราสามารถแทนที่ for-loop ด้วยการเรียกซ้ำแทน:

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

ส่วนใหญ่จะ golfed นี้:

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
คุณไม่สามารถใช้String[]แทนการใช้ varargs ได้ใช่ไหม (ประหยัดอีก 1 ไบต์)
Kritixi Lithos

@KritixiLithos อืม .. จุดดี แต่ส่วนใหญ่ขึ้นอยู่กับความยืดหยุ่นของอินพุตสำหรับความท้าทาย หากรูปแบบการป้อนข้อมูลใด ๆ ที่ได้รับอนุญาตกว่านั้นจะสั้นลงอย่างแน่นอน ฉันจะเพิ่มลงในเคล็ดลับนี้ขอบคุณ
Kevin Cruijssen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.