2008-08-28 73 views
13

編譯器是否可能從生產代碼中刪除用於調試目的(例如日誌記錄)的語句?調試語句需要以某種方式進行標記,也許使用註釋。如何從Java中的生產代碼中刪除調試語句

很容易設置屬性(debug = true)並在每個調試語句中檢查它,但這會降低性能。如果編譯器只是簡單地使調試語句消失,那將會很好。

回答

22

兩條建議。

第一個: 對於真正的日誌記錄,使用現代日誌包如log4j或java自帶的內置日誌記錄。不要擔心性能如此之高,日誌記錄級別檢查大約爲納秒。 (這是一個整數比較)。

如果你有超過一個日誌語句的更多,守護整個街區:

(log4j的,例如:)

if (logger.isDebugEnabled()) { 

    // perform expensive operations 
    // build string to log 

    logger.debug("...."); 
} 

這使您可以在運行時增加的能力控制記錄。必須重新啓動並運行調試版本可能非常不方便。

二:

你會發現assertions更多你所需要的。斷言是其計算結果爲布爾結果的聲明,並附上可選的消息:

assert (sky.state != FALLING) : "The sky is falling!"; 

每當斷言導致假,則斷言失敗和一個AssertionError是包含您的消息拋出(這是一個未經檢查的異常,打算退出應用程序)。

整潔的事情是,這些被JVM特別處理,並且可以在運行時切換到類級別,使用VM參數(不需要重新編譯)。如果未啓用,則零開銷。

10
public abstract class Config 
{ 
    public static final boolean ENABLELOGGING = true; 
} 

import static Config.*; 

public class MyClass 
{ 
    public myMethod() 
    { 
     System.out.println("Hello, non-logging world"); 

     if (ENABLELOGGING) 
     { 
      log("Hello, logging world."); 
     } 
    } 
} 

編譯器將刪除與代碼塊「你好,世界記錄。」其中如果ENABLE_LOGGING設置爲true,因爲它是一個靜態的最終值。如果你使用混淆器如proguard,那麼Config類也將消失。

的混淆也允許這樣的事情,而不是:

public class MyClass 
{ 
    public myMethod() 
    { 
     System.out.println("Hello, non-logging world"); 

     Log.log("Hello, logging world."); 
    } 
} 

import static Config.*; 

public abstract class Log 
{ 
    public static void log(String s) 
    { 
     if (ENABLELOGGING) 
     { 
      log(s); 
     } 
    } 
} 

方法日誌#日誌將減少至沒有在編譯器,並通過混淆與任何刪除,沿調用該方法,最終甚至Log類本身也會被刪除。

0

Java包含某種自己的預處理器。它被稱爲APT。它處理並生成代碼。目前我不確定這應該如何工作(我還沒有嘗試過)。但它似乎被用於這些事情。

-2

直接回答你的問題:我不知道。

但這裏是另一種解決問題的方法: 在我看來,有兩種說法,它們相互碰撞,在這裏:「調試聲明」和「生產代碼」。

調試語句的目的是什麼? (單元)測試時幫助擺脫錯誤。如果一塊軟件經過適當的測試並按照要求工作,那麼調試語句就沒有其他問題,只能是OBSOLETE。

我強烈反對在生產代碼中留下任何調試語句。我敢打賭,沒人會在生產代碼中測試調試代碼的副作用。代碼可能做它應該做的事情,但它做的比這更多嗎?你所有的#define是否都能正常工作,並真正把所有的調試代碼拿出來?誰分析了100000行預處理代碼,以查看所有調試內容是否消失?

除非我們有不同的生產代碼定義,否則在代碼測試完成後應考慮取出調試語句。

+3

如果您必須調試生產系統(無調試器),生產代碼中的調試語句可以成爲救生員。而軟件永遠不會「經過適當測試和正常工作」,你越來越近...... – sleske 2009-03-27 20:55:51

+0

你想擦除可能有數百個調試語句嗎?當你繼續發展時再添加它們?很抱歉,這就是爲什麼#DEFINE首先被髮明出來的原因。此外,這是Java,而不是C. 爲什麼回答一個問題,如果你不知道? – Lodewijk 2013-03-26 21:49:58

0

我也強烈建議使用日誌框架。

logger.IsDebugEnabled()不是強制性的,只是在記錄之前檢查系統是否處於調試級別會更快。

使用日誌框架意味着您可以在不重新啓動應用程序的情況下即時配置日誌級別。

你可以有記錄,如:

logger.error("Something bad happened") 
logger.debug("Something bad happend with loads more detail") 
1

另一種可能是把你的日誌記錄功能中的if語句,你會得到更少的代碼這種方式,但在一些額外的函數調用的開銷。

我也不是完全刪除調試代碼的大粉絲。一旦生產完成,如果出現問題,您可能需要訪問調試消息。如果你刪除了所有的代碼級調試,那麼這是不可能的。

0

這種「trick」似乎使您的調試語句消失

public static final boolean DEBUG = false; 

if (DEBUG) { //disapeared on compilation } 

post說,javac是足夠聰明檢查static final boolean和排除調試語句。 (我沒有親自嘗試)

對於記錄,我個人DONOT喜歡看這樣的代碼:

if (logger.isDebugEnabled()) { 
    logger.debug("...."); 
} 
realImportantWork(); 

日誌記錄的事情分散我從realImportantWork()。對我來說,正確的做法是:

logger.debug("...."); 
realImportantWork() 

加上不包括在生產的所有調試信息的配置。

我的意思是,logger.isDebugEnabled()控件應該是日誌框架的工作,而不是我的工作。大多數日誌框架支持像「logger」,「LogLevel」這樣的概念,它可以做到這一點。