Wskazówki dotyczące gry w golfa w Javie


86

Czy są jakieś przydatne skróty, których można używać w Javie?

Jak pokazano poniżej, importjuż dodaje co najmniej 17 znaków do programu.

import java.io.*;

Rozumiem, że prostym rozwiązaniem byłoby użycie innego języka, ale skrócenie programów Java wydaje się prawdziwym wyzwaniem.


Wskazówki powinny być specyficzne dla języka Java: jeśli dotyczą większości języków podobnych do języka C, należą do bardziej ogólnej listy wskazówek .


9
packagemożna pominąć.
st0le,

W odpowiedzi, czy nie mogę po prostu pominąć importu, zakładając, że on istnieje?
Fabricio

1
@Fabricio Nie, chyba że OP tak określi.
nyuszika7h

32
Najlepsza wskazówka na temat golfa Java: nie używaj go. ;)
kirbyfan64sos

4
„Chcę grać w golfa w java” powodzenia
sagiksp

Odpowiedzi:


85
  • Użyj najnowszej możliwej wersji Java. Java 8 pozwala używać wyrażeń lambda, więc używaj go, jeśli trzeba nawet nic podobnego obiektów funkcjonalnych.

  • Zdefiniuj skrócone funkcje dla rzeczy, których często używasz. Na przykład masz sto wywołań exampleClassInstance.doSomething(someParameter), zdefiniuj nową funkcję void d(ParameterType p){exampleClassInstance.doSomething(p)}i użyj jej, aby zapisać sobie kilka znaków.

  • Jeśli używasz określonej długiej nazwy klasy więcej niż raz, na przykład

    MyEventHandlerProxyQueueExecutorServiceCollectionAccessManagerFactory

    zamiast tego zdefiniuj nową klasę:

    class X extends MyEventHandlerProxyQueueExecutorServiceCollectionAccessManagerFactory{}

    Jeśli używasz tylko jednej konkretnej metody tej klasy (ale nadal musisz ją utworzyć), możesz jednocześnie zdefiniować skróconą wersję wewnątrz nowej klasy.

  • Użyj parametrów typu funkcji, aby skrócić rzeczy, tam gdzie to możliwe, na przykład:

    <T>void p(T o){System.out.println(o);}
  • Użyj for(;;)zamiast while(true).

  • Nie używaj modyfikatorów dostępu, chyba że jest to absolutnie konieczne.

  • Nie używaj finaldo niczego.

  • Nigdy nie umieszczaj bloku po forpętli (ale pętla foreach for(x:y)jest inna). Dodatkowe instrukcje powinny być umieszczone wewnątrz forsamej instrukcji, np for(int i=0;i<m;a(i),b(++i))c(i);.

  • Użyj wbudowanego przypisania, inkrementacji, tworzenia instancji. W razie potrzeby używaj anonimowych klas wbudowanych. Zamiast tego użyj lambdas, jeśli to możliwe. Wywołania funkcji Nest. Niektóre funkcje gwarantują, że zwrócą swój obiekt nadrzędny, te faktycznie są nawet przeznaczone do połączenia w łańcuch.

  • Twoje mainmetody throws Exceptionich nie łapią.

  • Errorjest krótszy niż Exception. Jeśli z jakiegoś powodu naprawdę potrzebujesz throwwiadomości na stosie, użyj Error, nawet jeśli jest to całkowicie normalna sytuacja.

  • Jeśli jakiś warunek wymagałby natychmiastowego rozwiązania, użyj int a=1/0;zamiast throw null;lub System.exit(0);. W czasie wykonywania powoduje to wyrzucenie ArithmeticException. Jeśli masz już w kodzie zmienną numeryczną, użyj jej zamiast tego. (Jeśli już masz import static java.lang.System.*;, idź z exit(0);.)

  • Zamiast implementować interfejsy, na przykład List<E>, rozszerz bezpośrednią (lub nie tak natychmiastową, jeśli jest to w ogóle jakąś zaletą) klasę potomną, na przykład AbstractList<E>, która zapewnia domyślne implementacje większości metod i wymaga tylko implementacji kilka kluczowych elementów.

  • Najpierw wypisz swój kod, używając znaków nowej linii, wcięć i pełnych nazw zmiennych. Gdy masz już działający kod, możesz skracać nazwy, przenosić deklaracje i dodawać metody skrótów. Pisząc go na długo, dajesz sobie więcej możliwości uproszczenia programu jako całości.

  • Porównaj alternatywne optymalizacje z fragmentem kodu, ponieważ najbardziej optymalna strategia może się radykalnie zmienić przy bardzo niewielkich zmianach w kodzie. Na przykład:

    • Jeśli masz tylko do dwóch połączeń do Arrays.sort(a), najbardziej skutecznym sposobem jest wywołanie go z jego nazwy w pełni kwalifikowanej java.util.Arrays.sort(a).
    • Przy trzech lub więcej połączeniach bardziej efektywne jest dodanie metody skrótu void s(int[]a){java.util.Arrays.sort(a);}. W tym przypadku nadal powinno się używać pełnej nazwy. (Jeśli potrzebujesz więcej niż jednego przeciążenia, prawdopodobnie robisz to źle).
    • Jeśli jednak twój kod musi w pewnym momencie skopiować tablicę (zwykle przy krótkiej forpętli podczas gry w golfa, przy braku łatwo dostępnej metody bibliotecznej), możesz skorzystać z Arrays.copyOfzadania. Gdy używana jest więcej niż jedna metoda, a są 3 lub więcej wywołań, wykonywanie import static java.util.Arrays.*;jest najbardziej efektywnym sposobem odwoływania się do tych metod. Następnie, tylko jeśli masz więcej niż 8 osobnych połączeń, sortpowinieneś użyć do tego metody skrótu i ​​tylko przy 5 lub więcej połączeniach jest to uzasadnione skrótem copyOf.

    Jedynym prawdziwym sposobem przeprowadzenia takiej analizy kodu jest faktyczne wykonanie potencjalnych modyfikacji na kopiach kodu, a następnie porównanie wyników.

  • Unikaj używania someTypeValue.toString();metody, zamiast tego po prostu dołącz someTypeValue+"".

  • Jeśli potrzebujesz systemu Windows, nie używaj Swinga, użyj AWT (chyba że naprawdę potrzebujesz czegoś od Swinga). Porównaj import javax.swing.*;i import java.awt.*;. Dodatkowo, składniki Swing posiada Jdołączany do ich nazwy ( JFrame, JLabelitp), ale składniki AWT nie ( Frame, Labelitp)


43

Użyj interfacezamiast class.

W java 8 do interfejsów dodano metody statyczne. W interfejsach wszystkie metody są domyślnie publiczne. w konsekwencji

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

można teraz skrócić do

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

który jest oczywiście krótszy.

Na przykład skorzystałem z tej funkcji w Hello, World! wyzwanie.


8
Nie wiedziałem tego! +1, niezła sztuczka
HyperNeutrino

Tak, mniej bojlera!
CalculatorFeline

3
Muszę częściowo się nie zgodzić (także pokonałem cię w wyzwaniu „Witaj, świecie!”, Używając tej techniki).
Olivier Grégoire

37

Za pomocą varargs możesz „rzutować” parametr na tablicę tego samego typu:

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

zamiast

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

31

Ze statycznym importem :

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

możesz później zapisać jakiś szablon, ale potrzebujesz wielu inwokacji, aby osiągnąć wypłatę:

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

8
: O. Możesz to zrobić?! I cały czas myślałem, że to niemożliwe Java!
Justin,

12
możesz nawet użyć import static java.lang.System.*.
Johannes Kuhn,

1
Wiem, że to stara odpowiedź, ale w Javie 10 możesz teraz zrobić to, var o=System.out;czego trzeba użyć tylko dwa razy, zanim się opłaci
Luke Stevens,

@LukeStevens: Cóż, może znajdziesz jakieś inne ulepszenia, możliwe w Javie 10, i tworzysz osobną odpowiedź na temat Java10?
użytkownik nieznany

1
@LukeStevens Czy var o=System.out.printlndziałałoby?
MilkyWay90

25

Argumentu do mainnie trzeba wywoływać args, a można wyciąć białe znaki:

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

zrobi dobrze.


1
Czy odpowiedzi muszą zawierać główną funkcję, jeśli nie zawiera wyraźnego oświadczenia o napisaniu pełnego programu? Użyłem wyrażeń lambda jako odpowiedzi.
Makotosan

3
@Mototosan Nie, oni nie; Jagnięta zwykle są w porządku.
daniero

21

Jeśli kiedykolwiek będziesz musiał użyć wyrażeń boolowskich truelub false, zamień je odpowiednio na 1>0i 1<0.

Na przykład:

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

Ten przykład wyszukiwania liniowego można zredukować do

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

11
Jeśli będziesz potrzebować dużo true/false, po prostu dodaj boolean t=1>0,f=1<0;. Następnie zamiast 1>0, użyj ti zapisz dwa znaki na użycie. Wypłata za 1>0metodę następuje przy 10 zastosowaniach.
Geobits

24
@Geobits: boolean t=1>0,f=!t;- o jeden char krótszy!
Bobbel

6
Przykład nie jest zbyt dobry. W tym przypadku i wielu (!) Innych można uniknąć używania true/ falsebezpośrednio: f|=a[i++]==42;dużo oszczędza.
Ingo Bürk

@ IngoBürk True. Kiedy to pisałem, głównie myślałem o funkcjach bibliotecznych, które wykorzystują boolean, ale ponieważ nie mogłem wymyślić żadnych przykładów w momencie pisania (zwykle nie koduję w Javie), po prostu napisałem prosty przykład.
ace_HongKongIndependence

1
@Geobits nie jest zbyt obeznany z javą, ale czy mógłbyś po prostu zdefiniować 1 i użyć t i! T (znowu nie znam Javy, po prostu jestem ciekawy)
Albert Renshaw

20

Jeśli zamierzasz często używać jakiejś metody, przypisz jej klasę rezydentną do zmiennej. Na przykład przypisz System.outdo zmiennej:

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

Także dla Integer.parseInt():

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

To prawie na pewno wywoła ostrzeżenie ide o „dostępie do metody statycznej ze zmiennej”


((Integer)1).parseInt("1")też działa.
Magic Octopus Urn

5
@carusocomputing new Integer("1")jest jeszcze krótszy. Ale Justin miał na myśli swoją odpowiedź, że możesz ponownie wykorzystywać zmienne, które już masz, do wywołań statycznych. Jak wyjaśniam na dole tej odpowiedzi.
Kevin Cruijssen

19

Zamiast korzystać z import static java.lang.System.*techniki zapisywania println()instrukcji, odkryłem, że zdefiniowanie następującej metody jest znacznie bardziej skuteczne w zapisywaniu znaków:

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

Wynika to z faktu, że można go przywoływać, p(myString)a out.println(myString)nie o wiele szybciej i bardziej dramatycznie.


19

Może się to wydawać oczywiste, ale dla niektórych Mathfunkcji dostępne są krótsze opcje :

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

Jeśli potrzebujesz Integer.MAX_VALUE(2147483647), użyj -1>>>1. Integer.MIN_VALUE(-2147483648) jest lepiej napisany 1<<31.


14

Jeśli chcesz pobrać liczbę z argumentu (lub dowolnego innego ciągu), zwykle widzisz coś takiego:

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

Wiele razy, nie trzebaInteger . Wiele wyzwań nie wykorzystuje dużych liczb. Ponieważ Shorti Byteoba rozpakują się na int, użyj valueOf()zamiast tego bardziej odpowiedniego i zapisz kilka bajtów.

Zachowaj jednak rzeczywistą zmienną jako int, ponieważ jest krótsza niż obie bytei short:

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

Jeśli musisz to zrobić dla wielu numerów, możesz połączyć z tą metodą :

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

9
int n=new Byte(a[0]);jest trzy razy krótszy. Jeśli liczba może być większa, użyj long n=new Long(a[0]), intw większości przypadków nadal jest lepsza niż s.
Ypnypn,

14

Nie używać public class. Główna metoda musi być publiczna, ale jej klasa nie. Ten kod działa:

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

Możesz biegać, java Snawet jeśli class Snie jest to klasa publiczna. ( Aktualizacja: Kiedy pisałem tę wskazówkę, korzystałem z Java 7. W Javie 8 twoja główna metoda powinna być w interfejsie . W Javie 5 lub 6 twoja główna metoda powinna być wyliczona .)

Wielu programistów Java tego nie wie! Około połowa odpowiedzi na pytanie przepełnienia stosu dotyczące main w klasie niepublicznej błędnie twierdzi, że główna metoda musi być w klasie publicznej. Teraz wiesz lepiej. Usuń publicin public classi zaoszczędzić 7 znaków.


1
O ile nie celujesz w Javę przed wersją 1.8, konstrukcja interface s{static void main(String[]...jest krótsza. Jeśli potrzebujesz kompilowalnego pliku źródłowego i głównej metody. Ponieważ w interfejsie Java 1.8 wszystkie metody są publiczne, więc można pominąć modyfikator metody.
Douglas odbył się

Ostatnio nie korzystałem z Javy, więc moja odpowiedź staje się nieaktualna. Zapomniałem, że interfejsy mogą mieć metody w Javie 8.
kernigh

Nie nauczyłem się tego od programowania; Nauczyłem się tego od gry w golfa :)
Douglas odbył się

14

Kilka małych wskazówek do gry w golfa

Te wskazówki były trochę za małe, aby rozdzielić odpowiedzi, więc wykorzystam tę odpowiedź do bardzo małych wskazówek dotyczących kodowania, które znalazłem lub wymyśliłem i nie zostały jeszcze wspomniane w innych poradach:

Usuwanie ostatniego znaku ciągu:

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

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

W niektórych przypadkach wiesz wcześniej, jaki jest ostatni znak, a także wiesz, że ta postać występuje tylko raz w ciągu. W takim przypadku możesz .splitzamiast tego użyć :

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

Skróty kodowania:

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

Wszystkie kodowania mają kanoniczną nazwę używaną w java.niointerfejsie API, a także kanoniczną nazwę używaną w interfejsach API java.ioi java.lang. Oto pełna lista wszystkich obsługiwanych kodowań w Javie. Dlatego zawsze używaj najkrótszego z dwóch; drugi jest zwykle krótszy (jak UTF-8vs utf8, Windows-1252vs Cp1252itp.), ale nie zawsze ( UTF-16BEvs UnicodeBigUnmarked).

Losowa wartość logiczna:

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

Liczby pierwsze:

Istnieje wiele różnych sposobów sprawdzania liczb pierwszych lub uzyskania wszystkich liczb pierwszych, ale odpowiedź @ SaraJ tutaj jest najkrótsza. Oto kopia-wklej jako odniesienie:

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

UWAGA: Zwykle możesz połączyć go z innymi istniejącymi pętlami, w zależności od tego, jak chcesz go używać, więc nie będziesz potrzebować oddzielnej metody. Na przykład zaoszczędziło to wiele bajtów w tej odpowiedzi .

Obcinanie liczb całkowitych zamiast Math.floor / Math.ceil:

Jeśli używasz dodatnich podwójnych / zmiennoprzecinkowych i chcesz floorich, nie używaj, Math.floorale (int)zamiast tego użyj -cast (ponieważ Java obcina się na liczbach całkowitych):

double d = 54.99;

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

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

// Outputs 54 for both

Tę samą sztuczkę można zastosować do ujemnych podwójnych / zmiennoprzecinkowych, które chcesz ceilzamiast tego:

double d = -54.99;

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

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

// Outputs -54 for both

Użyj &1zamiast %2pozbyć się nawiasu:

Ponieważ Operator Pierwszeństwo od &jest niższa niż standardowych operatorów arytmetycznych, jak */+-i %można pozbyć się nawiasów w niektórych przypadkach.

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

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

Zauważ, że to naprawdę nie pomaga w kontrolach boolean, ponieważ wtedy nadal potrzebujesz nawiasów, są one tylko trochę przesunięte:

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

BigIntegers i tworzenie zmiennych dla statycznych wywołań metod:

Korzystając z BigIntegers, utwórz go tylko raz, abyś mógł go ponownie użyć. Jak wiadomo, BigInteger zawiera pola statyczne ZERO, ONEa TEN. Więc kiedy używasz tylko tych trzech, nie potrzebujesz, importale możesz użyć java.Math.BigIntegerbezpośrednio.

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

UWAGA: Musisz użyć, =nullwięc tjest zainicjowany, aby użyć t..

Czasami możesz dodać wiele BigIntegerów, aby utworzyć kolejny, aby zapisać bajty. Powiedzmy, że chcesz mieć BigIntegers 1,10,12z jakiegoś powodu:

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

Jak słusznie zaznaczono w komentarzach, sztuczka z BigInteger t=null;wywołaniami metody statycznej może być również używana z innymi klasami.
Na przykład tę odpowiedź z 2011 r. Można pograć w golfa:

// 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() zamiast toCharArray()

Kiedy chcesz zapętlić znaki ciągu, zwykle robisz to:

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

Pętlowanie znaków może być przydatne podczas ich drukowania, dołączania do ciągu znaków lub czegoś podobnego.

Jednak, jeśli używać tylko znaków dla niektórych obliczeń numerycznych Unicode można zastąpić charz intI można zastąpić toCharArray()z getBytes():

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

Lub jeszcze krócej w Javie 8+:

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

W Javie 10+ zapętlanie znaku do wydruku można teraz wykonywać również w 22 bajtach:

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

Losowy przedmiot z 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

Sprawdź, czy ciąg znaków zawiera spacje wiodące / końcowe

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

Dlaczego to działa, gdy !=w Strings jest sprawdzanie referencji zamiast wartości w Javie? Ponieważ String#trimzwróci „ Kopię tego ciągu z usuniętą początkową i końcową białą spacją lub tego ciągu, jeśli nie ma wiodącej ani końcowej białej spacji . ” Użyłem tego, po tym, jak ktoś mi to zasugerował, w tej mojej odpowiedzi .

Palindrom:

Aby sprawdzić, czy Ciąg znaków jest palindromem (pamiętając o parzystych i nieparzystych długościach Ciągów), jest to najkrótszy ( .containsdziała tutaj, ponieważ wiemy, że zarówno Ciąg, jak i jego odwrócona postać są równej długości):

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

.contains(...)zamiast .equals(...+"")dzięki komentarzowi @assylias tutaj .

Albo jest 0, albo oba są 0?

Myślę, że większość już wie to jedno: jeśli chcesz sprawdzić, czy albo aczy bjest zero, zamiast mnożyć zapisać bajtów:

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

A jeśli chcesz sprawdzić, czy oba ai bsą zerowe, można użyć bitowym OR, lub dodać je razem, jeśli są zawsze pozytywne:

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)

Parzysty = 1, nieparzysty = -1; lub odwrotnie

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

Powodem, dla którego to dodałem, było po zobaczeniu k+(k%2<1?1:-1)w tej odpowiedzi :

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

nCzasy pętli w pełnym programie

Jeśli mamy wyzwanie, w którym pełny program jest obowiązkowy i musimy zapętlić określoną liczbę razy, możemy wykonać następujące czynności:

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

To samo dotyczy sytuacji, gdy musimy przyjąć ten zakres jako dane wejściowe:

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

Podziękowania dla @JackAmmo w tym komentarzu .

try-wreszcie zamiast try-catch (wyjątek e) podczas powrotu i kiedy go użyć

Jeśli nie możesz użyć, throws Exceptionale musisz catchcoś z tym zrobić przed powrotem, możesz finallyzamiast tego użyć :

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

Jako przykład, kiedy użyć a try-catch, mogę odnieść się do mojej odpowiedzi (uznanie dla pośredniego golfa należy do @KamilDrakari ). W tym wyzwaniu musimy zapętlić po przekątnej macierz NxM, więc musimy ustalić, czy liczba kolumn czy liczba wierszy jest najniższa jako nasze maksimum w pętli for (co jest dość drogie pod względem bajtów:) i<Math.min(a.length,a[0].length). Więc po prostu złapanie ArrayIndexOutOfBoundsExceptionużycia catch-finallyjest krótsze niż ta kontrola, a tym samym oszczędza bajty:

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

UWAGA: Działa to tylko z powodu return r;w końcu. Sugerowano mi zmodyfikowanie pierwszej komórki, tak jak @KamilDrakari zrobił w swojej odpowiedzi w języku C #, aby zapisać bajty. Jednak w Javie oznacza to, że będę musiał zmienić go na m->{try{for(int i=1;;m[0][0]=f(m[0][0],m[i][i++]));}catch(Exception e){}}(73 bajty), faktycznie zwiększając liczbę bajtów zamiast zmniejszać, gdybym mógł użyć finally.

Math.pow (2, n)

Jeśli potrzebujesz potęgi 2, nieco mądrzejsze podejście jest znacznie krótsze:

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

Łączenie bitowych i logicznych kontroli zamiast używania nawiasów

Myślę, że do tej pory jest to dobrze znane &i |może być używane zamiast &&i ||w sprawdzeniach logicznych Java (boolean). W niektórych przypadkach nadal chcesz używać &&zamiast &zapobiegać błędom, na przykład index >= 0 && array[index].doSomething. Jeśli &&zmieniono by na &tutaj, nadal będzie oceniać część, w której używa indeksu w tablicy, powodując ArrayIndexOutOfBoundsException, stąd użycie &&w tym przypadku zamiast &.

Jak dotąd podstawy &&/ ||vs &/ |w Javie.

Gdy chcesz to sprawdzić (A or B) and C, najkrótsze mogą się wydawać operatory bitowe:

(A|B)&C    // 7 bytes

Ponieważ jednak operatorzy bitowi mają pierwszeństwo operatorów przed sprawdzeniami logicznymi, możesz połączyć oba te elementy, aby zapisać bajt tutaj:

A|B&&C     // 6 bytes

Użyj n+=...-nzamiast(long)...

Kiedy masz zarówno wejście, jak i wyjście w lambda, na przykład podczas używania Math.pow, możesz zapisać bajt, używając n+=...-nzamiast (long)....
Na przykład:

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

Ten zapisany bajt w tej odpowiedzi kopalni , a nawet dwa bajty, łącząc -n-1się +~nw tej odpowiedzi kopalni .


Mówiąc bardziej ogólnie, do ostatniego punktu można uzyskać dostęp do elementów statycznych / wywoływać je z kontekstu niestatycznego, takiego jak instancja obiektu.
Poke

1
Nie rozumiem twojego napiwku. Dlaczego chcesz sufit positive integers? Nie jestem też pewien, czy wdrożenie pułapu działa .
Jonathan Frech,

1
since Java automatically floors on integers; Myślę, że właściwym terminem jest obcięcie , a nie podłoga .
Jonathan Frech,

1
Kolejna strategia PalindromuString t="";for(int i=s.length();--i>=0;t+=s.charAt(i));return s.equals(t);
Roberto Graham

1
@RobertoGraham Właściwie skopiowałem swój oryginalny kod z niewłaściwego wyzwania. Wystarczy s.equals(new StringBuffer(s).reverse()+"").
Kevin Cruijssen

11

Do gry w golfa, która nie wymaga danych wejściowych, możesz użyć bloków statycznych i uruchomić ją dobrze bez żadnej głównej metody, po prostu skompiluj ją z Javą 6.

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

1
Próbowałeś go skompilować i uruchomić? Blok jest uruchamiany, gdy klasa zostanie załadowana przez moduł ładujący klasy. Ale moduł ładujący klasy niczego nie załaduje, dopóki nie pozna klasy z główną metodą.
Cruncher,

@Cruncher Możesz obejść to sam, podpowiadając javaw wierszu poleceń / w pliku manifestu, którą klasę załadować.
AJMansfield

6
@Cruncher, to działało z Javą 6. Java 7 zmieniła sposób, w jaki działa.
Peter Taylor

1
Zgłasza wyjątek na końcu, ale działa! Nawet w Javie 7
stommestack

2
@JopVernooij Jeśli nie chcesz rzucać wyjątku na twarz, możesz system.exit (), ale zmarnujesz postacie, żadne wyzwanie golfowe nigdy nie prosi o unikanie wyjątków;)
Fabinout

11

Wszyscy wiemy o bitowej xor ( ^), ale jest to również logiczna xor.

Tak (a||b)&&!(a&&b)po prostu się staje a^b.

Teraz możemy użyć XOR.

Dodatkowo operatorzy, |a & także pracują , pamiętajcie tylko, że pierwszeństwo operatorów się zmienia.


5
Tak długo, jak pamiętasz pierwszeństwo, możesz używać, & a |także. Może to być przydatne, jeśli twoje warunki są już w nawiasach lub jeśli pracujesz już z logicznymi wartościami logicznymi.
Geobits

1
Jeśli potrzebujesz (znacznie) niższego priorytetu, możesz użyć !=zamiast ^dla xor, a ==dla xnor
Cyoce

11

Nie musisz używać Character.toLowerCase(char c). Zamiast tego użyj (c|32). Zamiast Character.toUpperCase(char c)używać (c&~32). Działa to tylko z literami ASCII.


c|~32spowoduje, że -1 ... lepiej użyć c-32.
feersum

5
@feersum To nie zadziałałoby, gdybyś chciał zrobić wielkie litery.
TheNumberOne

11

Konwertuj ciąg na liczbę

Istnieje wiele sposobów konwersji ciągu na wartość liczbową:

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

nowe ABC :

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

W przypadku gry w golfa najlepiej więc użyć konstruktora podczas konwertowania ciągu na wartość liczbową.

To samo dotyczy Double; Float; a Byte.


Nie zawsze ma to zastosowanie, gdy można ponownie użyć już istniejącej operacji podstawowej jako obiektu.
Jako przykład załóżmy, że mamy następujący kod:

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

Możesz użyć .decodezamiast krótszego konstruktora, ponownie wykorzystując parametr jako obiekt:

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

Nie używaj Random!

Ogólnie rzecz biorąc, jeśli potrzebujesz losowych liczb, Randomjest to okropny sposób na obejście tego *. Math.random()Zamiast tego znacznie lepiej jest użyć . Aby użyć Random, musisz to zrobić (powiedzmy, że potrzebujemy int):

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

Porównaj to z:

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

i:

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

Pierwsza metoda wymaga 41+15nznaków ( nto liczba wywołań). Drugi to 25npostacie, a trzeci to 43+7n.

Tak więc, jeśli potrzebujesz go tylko raz lub dwa razy, użyj Math.random()metody inline . W przypadku trzech lub więcej połączeń zaoszczędzisz za pomocą funkcji. Albo jeden zapisuje znaki na pierwszym użyciu ponad Random.


Jeśli używasz już Math.random()dla doublepamiętać, że w czterech zastosowań, to wciąż oszczędności go wyciągnąć na:

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

Za 33 znaki zaoszczędzisz 10 na każdym połączeniu z r()


Aktualizacja

Jeśli potrzebujesz liczby całkowitej i chcesz zaoszczędzić na przesyłaniu, nie przesyłaj jej! Automatyczne rzutowanie Java, jeśli wykonasz operację zamiast przypisania. Porównać:

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

* Chyba że musisz zasiać PRNG, aby uzyskać przewidywalne wyniki. W takim razie nie widzę większego rozwiązania.


2
Nie zapomnij o tym Random#nextGaussian.
Justin

@Quincunx Prawda, wykonanie matematyki w celu uzyskania prawidłowego rozkładu normalnego spowoduje utratę wszelkich oszczędności.
Odniosę

Zauważ, że (int)(Math.random()*9)ma bardzo małe odchylenie modulo, ponieważ Math.random()zwraca 2 53 możliwe wartości, a 2 53 nie jest wielokrotnością 9. Prawdopodobieństwo każdej liczby jest w zakresie 1/9 plus lub minus 5 / (9 * 2 ** 53), błąd tak mały, że prawie dokładnie 1/9.
kernigh

@ kernigh Racja, użyłem 9tylko jako przykładu, może to być wszystko. Jestem względnie pewien, że nextInt()(lub jakakolwiek inna Randommetoda) ma również niewielkie uprzedzenie, tylko ze względu na działanie PRNG Java.
Geobits

1
Coś związanego z tym, kiedy chcesz losowej wartości logicznej: zamiast new java.util.Random().nextBoolean()możesz użyć Math.random()<.5.
Kevin Cruijssen

7

Nie wiem, czy uważasz tę „czystą” Javę, ale Przetwarzanie umożliwia tworzenie programów z niewielką początkową konfiguracją (zakończoną automatycznie).

W przypadku wyjścia z konsoli możesz mieć coś tak prostego, jak:

println("hi"); //done

dla wyjścia graficznego, trochę więcej:

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 Doskonały zasób! Na pewno się z tym pobawię.
Rob

Czy byłoby dobrze, gdybym dodał odpowiedzi innych ludzi na ten? Czy może to przeczy celowi wiki społeczności?
Rob

2
Nawiasem mówiąc, wcale nie musisz dzwonić size; domyślnie będzie to kwadrat o wymiarach 100 na 100 pikseli. W większości systemów operacyjnych ramka wokół niego będzie około dwa razy większa, z kwadratem wyśrodkowanym, a reszta obszaru będzie wypełniona treścią pobraną z pulpitu.
AJMansfield,

1
Aby uzyskać wyjście graficzne, jeśli nie potrzebujesz animacji, możesz po prostu napisać wszystko poza setup()i draw()użyć „trybu statycznego”. Możesz także użyć 6-cyfrowych kolorów szesnastkowych, a tłumacz je zmieni, co czasem się opłaca ( #FF8000< 255,128,0), a jeśli używasz skali szarości, musisz podać tylko jedną liczbę ( 255< 255,255,255)
quat

7

Skrócenie powrotu

Możesz skrócić instrukcje zwrotne ciągów o bajt za pomocą:

return "something";

do

return"something";

A jeśli zdarzy się, że zaczniesz zwrot w nawiasie, możesz zrobić z nimi to samo:

return (1+taxRate)*value;

do

return(1+taxRate)*value;

Myślę, że cytaty są traktowane jak nawiasy? Właściwie to podniosłem to przez AppleScript i pomyślałem, że warto o tym wspomnieć.


1
To samo dotyczy znaków numerycznych, takich jak return-n;zamiast return -n;lub return~n;zamiast return ~n;. Oprócz singli zamiast podwójnych cytatów:return'A';
Kevin Cruijssen

1
Zasadniczo działa na wszystko, co nie może być częścią identyfikatora (tj. Nie jest literą ani jest cyfrą).
Paŭlo Ebermann

7

Nie bój się używać notacji naukowej

Jeśli masz do czynienia z liczbami podwójnymi lub zmiennoprzecinkowymi, możesz użyć notacji naukowej dla liczb. Zamiast pisać double a=1000, możesz zmienić go na double a=1e31 bajt.


7

Spróbuj użyć intzamiastboolean

W niektórych przypadkach stwierdziłem, że krótsze jest zwrócenie wartości całkowitej z metody, która normalnie zwróciłaby wartość logiczną, podobnie jak w programach C.

Zaraz nietoperz intjest o 4 bajty krótszy niż boolean. Za każdym razem, gdy piszesz return 0zamiast return 1<0, zapisujesz dodatkowe 2 bajty i to samo na return 1 ponad return 1>0.

Pułapka polega na tym, że za każdym razem, gdy chcesz użyć wartości zwracanej bezpośrednio jako logicznej, kosztuje ona 2 bajty ( if(p(n))v. if(p(n)>0)). Można to uzupełnić za pomocą arytmetyki logicznej. Biorąc pod uwagę wymyślony scenariusz, w którym chcesz pisać

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

możesz zamiast tego pisać

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

w celu zaoszczędzenia 2 bajtów.


6
Robię to dość często podczas gry w golfa, ale należy pamiętać, że ogólny konsensus jest taki 0i 1nie stanowią one fałszu / prawdy w Javie (a JLS też nie uważa ich w ten sposób). Jeśli więc golf pyta się o prawdę / fałsz, musisz to zrobić w trybie booleanizowanym (i, niestety, włączyć booleanfunkcję, dodając do tego jeszcze więcej bajtów).
Geobits,

2
t[0]+=p(n):10?0;Czy to w ogóle jest ważne?
dorukayhan

@dorukayhan nie, tak powinno być t[0]+=p(n)?10:0;. (Zredagowałem to.)
Paŭlo Ebermann

6

Jeśli użyjesz enum zamiast klasy , zapisujesz jedną postać.

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

    }
}

Ale musisz wprowadzić co najmniej jedną instancję wyliczenia (F, G, H w tym przykładzie), która musi się spłacić.


2
Wydaje się, że nie potrzebujesz żadnych wystąpień enum. Zrobiłem enum M{;public static void main(String[]a){...}bez problemów.
Danny

3
@ Danny Ale wtedy nie zapisuje żadnych znaków. class M{ma dokładnie taką samą długość jak enum M{;. W takim razie wybrałbym to, classponieważ jest ładniejsze (IMO)
Justin

1
przynajmniej dla mnie enum{pracował bez ;; to tylko IDE jęczy, że jest błąd, ale kompilator to akceptuje
masterX244

@ masterX244 Jaki kompilator / wersja? Mój wywołuje furię i nie chce tego zrobić.
Geobits

pracował dla java 1.7 dla mnie (pojawił się s, ned, aby zbadać dalszą przyczynę z aktualizacją do .8 przestał działać)
masterX244

5

Gdy masz metodę, która powinna zwrócić a booleanlub Boolean, tj .:

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

Możesz zmienić typ boolean/ Booleanreturn, Objectaby zapisać 1 bajt:

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

Ponadto, jak być może zauważyłeś, możesz użyć <1czeku zamiast ==0zapisać bajt. Chociaż jest to bardziej ogólna wskazówka dotycząca golfa zamiast specyficznych dla Javy.
Jest to najczęściej używane, gdy liczba całkowita nie może być ujemna, na przykład sprawdzanie długości:

a.length<1

zamiast

a.length==0

1
Dobra wskazówka! Aby to zilustrować, możesz dodać kolejny przykład w sekcji „jeśli nie może być ujemny”, ponieważ c(-21)wraca truez bieżącym.
Geobits

Wyjaśnione. Czy nie masz na myśli c(-20)zamiast -21? -21 % 5 = 4a -20 % 5 = 0.
Kevin Cruijssen

1
Nie, miałem na myśli -21. -21 % 5 != 4w Javie, o co mi chodzi. Podzielna przez pięć funkcji będzie działać prawidłowo, jeśli moduł zawsze zwrócony nieujemna, ale tak nie jest. Zobacz ten przykładowy fragment .
Geobits

@Geobits Ah, dzięki za przykład. Prawie nigdy nie używam liczb ujemnych %, więc zapomniałem, że Java zwraca resztę zamiast modułu, stąd różnica.
Kevin Cruijssen

5

Jak rysować w Javie ...

Oto najkrótsza możliwa płyta kotła lakierniczego GUI:

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

Grał w golfa za 111 bajtów:

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

5

Unikaj StringBuilders

Dołączanie rzeczy do Stringzajmuje dużo mniej bajtów.

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

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

Jeśli musisz odwrócić ciąg i wydrukować go od razu, użyj 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

Jeśli musisz odwrócić ciąg, a następnie zrobić coś innego niż wydrukowanie, użyj forkażdej pętli.

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

3
Pętla foreach jest krótsza niż StringBufferdla łańcuchów odwracających. String b="";for(char c:"Hello, World!".toCharArray()){b=c+b;}
Poke

1
Powinieneś również usunąć {}pętlę foreach, jeśli zamierzasz użyć tej metody.
Geobits

1
Zaoszczędź 2 bajty, używając String s:"".split("")zamiast char c:"".toCharArray().
charlie,

Jeśli java.util.stream.Streamjuż zaimportowałeś i jeśli chcesz połączyć kolejne wywołanie wyniku (jak B.chartAt(42)) lub jeśli chcesz tylko przekazać wynik do funkcji (jak f(B)), to użycie for(:)jest równe Stream.of("Hello, World!".split("")).reduce("",(a,b)->b+a).
charlie

Obie linie w twoim przykładzie z for-each można zagrać w golfa. Pierwszy może być: String b=new StringBuffer("Hello, World!").reverse()+"";( .toStringzastąpiony przez +""), a twój drugi wiersz może być: String B="";for(String c:"Hello, World!".split(""))B=c+B;( chardo Stringi .toCharArray()do .split("")).
Kevin Cruijssen

5

Użyj Java 10 var

Jeśli zdefiniujesz pojedynczą zmienną określonego typu, użyj var.

Przykłady

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

Nie można użyć w żadnym z poniższych przykładów

var nie można użyć w wielu przykładach

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, dlaczego to nie działa z odwołaniami do metod, zauważ, że istnieją standardowe interfejsy funkcjonalne tylko dla małego zestawu podpisów (a metody mogą zgłaszać sprawdzone wyjątki).
Jakob


4

W większości przypadków twój program będzie jednowątkowy, tzn. Będzie działał tylko jeden wątek. Możesz wykorzystać ten fakt, returnwchodząc z głównej metody, gdy musisz natychmiast wyjść.

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

Porównaj to z „prawidłowym” zakończeniem programu:

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

Lub wskazując na null:

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

Lub dzieląc przez 0:

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

4

Czasami pojedyncza instrukcja dla pętli może być wymienna. Rozważ następujący kod:

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

Jest to prosta pętla for będąca rozwiązaniem tego pytania .

Ponieważ wiemy, że inie będzie on wystarczająco duży, aby spowodować błędy StackOverflow, możemy zamiast tego zastąpić pętlę for rekurencją:

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

Możemy symulować pętlę za pomocą operatora trójskładnikowego w instrukcji return, aby spowodować rekurencję.

Ta redukcja jest raczej specyficzna, ale mogę sobie wyobrazić więcej sytuacji, w których byłoby to przydatne.


4

Wykorzystanie ...(varags) jako parametru

W niektórych przypadkach krócej jest używać varargs Java jako parametru zamiast luźnych.
Na przykład:

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

Grałby w większość do tego:

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

Ale można odegrać w tym dodatkowy bajt:

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

Zauważ, że wszystkie trzy liczby całkowite są dostępne tylko raz w samej metodzie. Ponieważ intjest on dość krótki, korzystne jest, jeśli użyjesz ich tylko raz w metodzie i podasz trzy lub więcej z nich jako parametr.

Przy dłuższych parametrach jest to zwykle bardziej przydatne. Na przykład, to była moja pierwotna odpowiedź na to wyzwanie (oblicz wystąpienie znaku wejściowego w ciągu wejściowym):

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

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

I zalecono mi grę w golfa do tego:

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

Ale skończyłem grać w golfa przy użyciu ...:

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

UWAGA: Jeśli pytanie / wyzwanie wymaga elastycznych danych wejściowych, ...można je []oczywiście skrócić . Jeśli pytanie / wyzwanie konkretnie wymaga, powiedzmy, trzech Stringdanych wejściowych i nie zezwala na Stringtablicę zawierającą trzy wartości, możesz użyć String...zamiast String a,String b,String c.


2
Czy nie możesz użyć String[]zamiast varargs? (zapisuje jeszcze 1 bajt)
Kritixi Lithos

@KritixiLithos Hmm .. dobry punkt. Ale to zależy głównie od elastyczności wkładu w wyzwanie. Jeśli jakikolwiek format wejściowy jest dozwolony, to rzeczywiście byłby krótszy. Dodam to do tych wskazówek, dzięki.
Kevin Cruijssen
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.