《Java解惑》系列——02字符谜题——谜题21:我的类是什么 升级版(string的replaceAll)

知识点:

String的replaceAll(str1,str2)方法,注意参数一和参数二的注意项。

参数一:reg字符串。Java中正则特殊处理,点“.”,反斜杠"\"等。使用Pattern.quote(str)解决

参数二:替代字符串。在替代字符串中使用反斜杠 (\) 和美元符号 ($) 与将其视为字面值替代字符串所得的结果可能不同。使用Matcher.quoteReplacement(str)解决


问题:

下面的程序所要做的事情正是前一个谜题所做的事情,但是它没有假设斜杠符号
就是分隔文件名组成部分的符号。相反,该程序使用的是
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"); 
    } 
} 

// 期望结果:com/javapuzzlers/MeToo.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类就没有很好地遵从这一原则。对许多程序员来说,
对于哪些字符串替代方法使用的是字面含义的字符串,以及哪些使用的是正则表
达式或替代字符串,要记住这些都不是一件容易事。 






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值