Java'da #ifdef #ifndef


106

Java'da derleme zamanı koşullarını C ++ 'da #ifdef #ifndef gibi yapmanın bir yolu olup olmadığından şüpheliyim.

Benim sorunum, Java ile yazılmış bir algoritmaya sahip olması ve farklı çalışma sürelerim bu algoritmaya göre gelişiyor. Bu yüzden her iyileştirme kullanıldığında ne kadar zaman kazandığımı ölçmek istiyorum.

Şu anda, çalışma süresi boyunca hangi iyileştirmenin kullanılması gerektiğine ve hangilerinin kullanılmayacağına karar vermek için kullanılan bir dizi boole değişkenine sahibim. Ancak bu değişkenleri test etmek bile toplam çalışma süresini etkiler.

Bu nedenle, derleme sırasında programın hangi bölümlerinin derlenmesi ve kullanılması gerektiğine karar vermenin bir yolunu bulmak istiyorum.

Java'da bunu yapmanın bir yolunu bilen var mı? Ya da belki birisi böyle bir yol olmadığını biliyordur (bu da yararlı olacaktır).

Yanıtlar:


126
private static final boolean enableFast = false;

// ...
if (enableFast) {
  // This is removed at compile time
}

Yukarıda gösterilen gibi koşullu ifadeler derleme zamanında değerlendirilir. Onun yerine bunu kullanırsan

private static final boolean enableFast = "true".equals(System.getProperty("fast"));

Daha sonra enableFast'e bağlı tüm koşullar JIT derleyicisi tarafından değerlendirilecektir. Bunun ek yükü önemsizdir.


Bu çözüm benimkinden daha iyi. Değişkenleri önceden ayarlanmış bir dış değerle başlatmaya çalıştığımda, çalışma süresi 3 saniyeye geri döndü. Ancak değişkenleri statik sınıf değişkenleri (ve bir fonksiyon yerel değişkeni değil) olarak tanımladığımda, çalışma süresi 1 saniyeye döndü. Yardım için teşekkürler.
jutky

6
IIRC, bu Java bir JIT derleyicisine sahip olmadan önce bile işe yarıyordu. Kod javacsanırım tarafından kaldırıldı . Bu sadece (diyelim) enableFastifadesi bir derleme zamanı sabiti ifadesiyse işe yaradı .
Stephen C

2
Evet, ama bu koşul bir yöntem içinde yer almalı, değil mi? Ayarlamak istediğimiz bir grup özel statik son Dizemizin olduğu durum ne olacak? (ör. üretim ve hazırlama için farklı ayarlanmış bir dizi sunucu URL'si)
tomwhipple

3
@tomwhipple: doğru, ayrıca bu şuna benzer bir şey yapmanıza izin vermiyor: private void foo(#ifdef DEBUG DebugClass obj #else ReleaseClass obj #endif )
Zonko

3
ithalata ne dersiniz (örneğin, sınıf yolu ile ilgili olarak)?
n611x007

44

javac ulaşılamayan derlenmiş bir kod çıktılamaz. Şunlara ait sabit bir değere nihai değişken seti kullanın #defineve normal ifiçin açıklamada #ifdef.

Erişilemeyen kodun çıktı sınıfı dosyasına dahil olmadığını kanıtlamak için javap'i kullanabilirsiniz. Örneğin, aşağıdaki kodu göz önünde bulundurun:

public class Test
{
   private static final boolean debug = false;

   public static void main(String[] args)
   {
       if (debug) 
       {
           System.out.println("debug was enabled");
       }
       else
       {
           System.out.println("debug was not enabled");
       }
   }
}

javap -c Test iki yoldan yalnızca birinin derlendiğini (ve if ifadesinin olmadığını) gösteren aşağıdaki çıktıyı verir:

public static void main(java.lang.String[]);
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc     #3; //String debug was not enabled
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   return

2
Bu javac'a özel mi yoksa bu davranış aslında JLS tarafından garanti ediliyor mu?
Pacerier

@pacerier, bunun JLS tarafından garanti edilip edilmediğine dair hiçbir fikrim yok, ancak 90'lardan beri karşılaştığım her java derleyicisi için doğruydu, 1.1.7'den önceki olası istisnalar dışında ve sadece bunu yapmadığım için o zaman test edin.

12

Sanırım çözümü buldum, çok daha basit.
Boolean değişkenlerini "final" değiştirici ile tanımlarsam, Java derleyicisi sorunu kendisi çözer. Çünkü bu durumu test etmenin sonucunun ne olacağını önceden biliyor. Örneğin bu kod:

    boolean flag1 = true;
    boolean flag2 = false;
    int j=0;
    for(int i=0;i<1000000000;i++){
        if(flag1)
            if(flag2)
                j++;
            else
                j++;
        else
            if(flag2)
                j++;
            else
                j++;
    }

bilgisayarımda yaklaşık 3 saniye çalışıyor.
Ve bu

    final boolean flag1 = true;
    final boolean flag2 = false;
    int j=0;
    for(int i=0;i<1000000000;i++){
        if(flag1)
            if(flag2)
                j++;
            else
                j++;
        else
            if(flag2)
                j++;
            else
                j++;
    }

yaklaşık 1 saniye çalışır. Bu kod aynı zamanda

    int j=0;
    for(int i=0;i<1000000000;i++){
        j++;
    }

1
Bu ilginç. Görünüşe göre JIT zaten koşullu derlemeyi destekliyor! Bu finaller başka bir sınıfta veya başka bir pakette olursa işe yarar mı?
joeytwiddle

Harika! O zaman bunun bir çalışma zamanı optimizasyonu olması gerektiğine inanıyorum, kod aslında derleme zamanında soyulmuyor. Olgun bir sanal makine kullandığınız sürece sorun değil.
joeytwiddle

@joeytwiddle, Anahtar kelime olgun bir sanal makineyi "kullandığınız sürece" demektir.
Pacerier

2

Hiç kullanmadım ama bu var

JCPP, C ön işlemcisinin eksiksiz, uyumlu, bağımsız, saf bir Java uygulamasıdır. Java'da sablecc, antlr, JLex, CUP ve benzeri araçlar kullanarak C-stili derleyiciler yazan kişilerin kullanması amaçlanmıştır. Bu proje, GNU C kütüphanesinin kaynak kodunun çoğunun başarılı bir şekilde ön işlemesi için kullanılmıştır. 1.2.5 sürümünden itibaren, Apple Objective C kitaplığını da ön işleyebilir.

http://www.anarres.org/projects/jcpp/


1
Bunun ihtiyacıma uygun olduğundan emin değilim. Kodum Java ile yazılmış. Belki bana onların kaynaklarını almamı ve bunları koduma ön işlem yapmak için kullanmamı öneriyorsunuz?
jutky

2

Koşullu derlemeye gerçekten ihtiyacınız varsa ve Ant kullanıyorsanız , kodunuzu filtreleyebilir ve içinde arama ve değiştirme yapabilirsiniz.

Örneğin: http://weblogs.java.net/blog/schaefa/archive/2005/01/how_to_do_condi.html

Aynı şekilde, örneğin, yerine bir filtre yazabilir LOG.debug(...);ile /*LOG.debug(...);*/. Bu if (LOG.isDebugEnabled()) { ... }, aynı zamanda daha kısa olmaktan bahsetmemekle birlikte, her şeyden daha hızlı işleyecektir.

Eğer kullanırsanız Maven'i , tarif benzer özellik var burada .


2

Manifold , tamamen entegre bir Java ön işlemcisi sağlar (oluşturma adımları veya oluşturulmuş kaynak yoktur). Özel olarak koşullu derlemeyi hedefler ve C-tarzı yönergeleri kullanır.

Manifold'un Java Ön İşlemcisi


1

Bir sınıfın uygulamaları arasında geçiş yapmak için Fabrika Modeli kullanılsın mı?

Nesne oluşturma zamanı artık bir endişe olamaz, değil mi? Uzun bir çalışma süresinin ortalaması alındığında, harcanan zamanın en büyük bileşeni artık ana algoritmada olmalı, değil mi?

Açıkçası, ulaşmak istediğiniz şeyi yapmak için gerçekten bir ön işlemciye ihtiyacınız yok. Muhtemelen ihtiyacınızı karşılamanın elbette önerdiğimden başka yolları vardır.


Değişiklikler çok küçük. İstenen sonucu yeniden hesaplamak yerine önceden bilmek için bazı koşulları test etmek gibi. Bu nedenle, işleve çağrı ek yükü benim için uygun olmayabilir.
jutky

0
final static int appFlags = context.getApplicationInfo().flags;
final static boolean isDebug = (appFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.