2012-06-06 10 views
13

Wiem, że asercje mogą być włączone/wyłączone w środowisku wykonawczym odpowiednio do debugowania i produkcji. Jednak stwierdziłem, że asercje zwiększają również rozmiar generowanego pliku binarnego (około 100-200 bajtów w poniższym przykładzie).Kompilowanie bez twierdzeń

W C i C++, możemy to zrobić w czasie kompilacji, mając #define NDEBUG przed #include <assert.h>.

Czy jest jakiś sposób, aby kompilator Java automatycznie to zrobił? Chciałbym zostawić je w kodzie źródłowym do późniejszego debugowania. Ale nie chcę również, aby wynikowy plik binarny był większy niż jest to konieczne (mamy limit rozmiaru jako wymaganie projektu).

kod C:

//#define NDEBUG 
#include <assert.h> 

int main(void) { 
    assert(0); // +200 bytes without NDEBUG, 0 with NDEBUG 
    return 0; 
} 

Java kod:.

public class Test { 
    public static void main(String[] args) { 
     assert(System.nanoTime()==0); // increases binary size by about 200 bytes 
    } 
} 

W odpowiedzi na bn na odpowiedź:

public class Test2 { 
    public static final boolean assertions = false; 

    public static void main(String[] args) { 
     if(assertions) { 
      assert(System.nanoTime()==0); 
     } 
    } 
} 

EDIT: Faktycznie, wydaje się, dla mnie to włączanie/wyłączanie jest bardziej użytecznym kompilatorem e funkcja niż czas działania. Chodzi mi o to, ilu użytkowników końcowych je włączy? Jeśli chodzi o programistę podczas procesu debugowania, prawdopodobnie i tak będzie on rekompilował kod.

+0

Nie dowodzi to, że każdy dowód kosztuje 200 bajtów, tyle tylko, że tak. – EJP

+1

@EJP: Na pewno.Chodziło mi o to, że istnieje niezaprzeczalny wzrost spowodowany przez twierdzenia jako całość. Dokładna kwota z pewnością zależy od złożoności oświadczenia. – tskuzzy

+1

Jeśli zawracasz sobie tym głowy, jesteś w niewłaściwym języku. – lvella

Odpowiedz

2

osobiście Nie należy wykonać następujące czynności ze względu na złożoność dodany do kodu źródłowego, ale javac generowane dokładnie ten sam kod pośredni dla main w dwóch fragmentów:

warunkowego dochodzi

class C { 
    public final static boolean assertions = false; 

    public static void main(String[] args) { 
     if(assertions) { 
      assert(System.nanoTime()==0); 
     } 
    } 
} 

nie twierdzi

class C { 
    public static void main(String[] args) { 
    } 
} 

skompilowany kod

public static void main(java.lang.String[]); 
    Code: 
     0: return   
    LineNumberTable: 
     line 3: 0 

EDIT

W rzeczywistości wydaje mi się, że to włączenie/wyłączenie jest bardziej przydatna funkcja kompilacji niż raz wyciekami. Chodzi mi o to, ilu użytkowników końcowych będzie w stanie je włączyć?

Nie jest to użytkownik końcowy, który je obsługuje, to obsługa klienta informuje użytkownika końcowego, aby je włączyć. Żałuję, że nie były domyślnie włączone, a nie wyłączone.

+0

Doskonałe dzięki! Zgadzam się, że to nie jest bardzo eleganckie rozwiązanie, ale odpowiada na moje pytanie. – tskuzzy

+0

Wygląda na to, że jeśli umieścisz "public final static asercje = false;" zmienna na oddzielnej klasie, tak abyś mógł użyć całego kodu i zmienić flagę w jednym miejscu, będziesz musiał przekompilować całość źródło, jeśli jest zmienione (i jest to pożądane, ponieważ chcesz, aby zmienna została wymazana ze skompilowanego kodu). – lvella

+0

@Ivella to dlatego, że kompilator włącza publiczne finały statyczne. –

4

Nie jest to możliwe jako wbudowany krok kompilacji. Możesz jednak to zrobić, dodając bloki warunkowe wokół swoich asercji.

Aby uzyskać więcej informacji, zobacz artykuł "Removing all Trace of Assertions from Class Files".

+0

Brzmi to jak dobry pomysł, ale w rzeczywistości zwiększyło binarne jeszcze bardziej o kolejne 50 bajtów. – tskuzzy

+0

To nie ma większego sensu, ponieważ kompilator powinien całkowicie usunąć instrukcje, ponieważ jest on nieosiągalny. – Robin

+2

@Robin, jeśli OP użyje "końcowego", zmniejszy rozmiar. –