1. 程式人生 > >謎題21:我的類是什麽?

謎題21:我的類是什麽?

文件分隔 轉換 部分 新的 哪些 fbo print 組成 引入

下面的程序所要做的事情正是前一個謎題所做的事情,但是它沒有假設斜杠符號就是分隔文件名組成部分的符號。相反,該程序使用的是java.io.File.separator,它被指定為一個公共的String域,包含了平臺相關的文件名分隔符。那麽,這個程序會打印出其正確的、平臺相關的類文件名嗎?


package com.javapuzzlers;

import java.io.File;

public class MeToo {

    public static void main(String[] args){

        System.out.println(MeToo.class.getName().

            replaceAll("\\.", File.separator) + ".class");

    }

}

這個程序根據底層平臺的不同會顯示兩種行為中的一種。如果文件分隔符是斜杠,就像在UNIX上一樣,那麽該程序將打印com/javapuzzlers/MeToo.class,這是正確的。但是,如果文件分隔符是反斜杠,就像在Windows上一樣,那麽該程序將打印像下面這樣的內容:


Exception in thread "main" 

java.lang.StringIndexOutOfBoundsException: String index out of range: 1

        at java.lang.String.charAt(String.java:558)

        at java.util.regex.Matcher.appendReplacement(Mather.

java:696)

        at java.util.regex.Matcher.replaceAll(Mather.java:806)

        at java.lang.String.replaceAll(String.java:2000)

        at com.javapuzzlers.MeToo.main(MeToo.java:6)

盡管這種行為是平臺相關的,但是它並非就是我們所期待的。在Windows上出了什麽錯呢?

事實證明,String.replaceAll的第二個參數不是一個普通的字符串,而是一個替代字符串(replacement string),就像在java.util.regex規範中所定義的那樣[Java-API]。在替代字符串中出現的反斜杠會把緊隨其後的字符進行轉義,從而導致其被按字面含義而處理了。

當你在Windows上運行該程序時,替代字符串是單獨的一個反斜杠,它是無效的。不可否認,拋出的異常應該提供更多一些有用的信息。

那麽你應該怎樣解決此問題呢?5.0版本提供了不是一個而是兩個新的方法來解決它。第一個方法是java.util.regex.Matcher.quoteReplacement,它將字符串轉換成相應的替代字符串。下面展示了如何使用這個方法來訂正該程序:


System.out.println(MeToo.class.getName().replaceAll("\\.", Matcher.quoteReplacement(File.separator)) + ".class");

引入到5.0版本中的第二個方法提供了一個更好的解決方案。該方法就是String.replace(CharSequence, CharSequence),它做的事情和String.replaceAll相同,但是它將模式和替代物都當作字面含義的字符串處理。下面展示了如何使用這個方法來訂正該程序:


System.out.println(MeToo.class.getName().replace(".", File.separator) + ".class");

但是如果你使用的是較早版本的Java該怎麽辦?很遺憾,沒有任何捷徑能夠生成替代字符串。完全不使用正則表達式,而使用String.replace(char,char)也許要顯得更容易一些:


System.out.println(MeToo.class.getName().replace(‘.’, File.separatorChar) + ".class");

本謎題和前一個謎題的主要教訓是:在使用不熟悉的類庫方法時一定要格外小心。當你心存疑慮時,就要求助於Javadoc。還有就是正則表達式是很棘手的:它所引發的問題趨向於在運行時刻而不是在編譯時刻暴露出來。

對API的設計者來說,使用方法具名的模式來以明顯的方式區分方法行為的差異是很重要的。Java的String類就沒有很好地遵從這一原則。對許多程序員來說,對於哪些字符串替代方法使用的是字面含義的字符串,以及哪些使用的是正則表達式或替代字符串,要記住這些都不是一件容易事。

謎題21:我的類是什麽?