看jdk的string类源代码:
 public String toUpperCase(Locale locale) {
if (locale == null) {//偶不明白为什么这儿要判断一下,是否抛出空指针。因为空指针在运行的时候可以由jvm捕获的呀????
    throw new NullPointerException();
        }        int     firstLower; /* Now check if there are any characters that need to be changed. */
scan: {
    for (firstLower = 0 ; firstLower < count; ) {
int c = (int)value[offset+firstLower];
int srcCount;
if ((c >= Character.MIN_HIGH_SURROGATE) &&
    (c <= Character.MAX_HIGH_SURROGATE)) {
    c = codePointAt(firstLower);
    srcCount = Character.charCount(c);
} else {
    srcCount = 1;
}
int upperCaseChar = Character.toUpperCaseEx(c);
if ((upperCaseChar == Character.ERROR) ||
    (c != upperCaseChar)) {
    break scan;
}
firstLower += srcCount;
    }
    return this;
}        char[]  result       = new char[count]; /* may grow */
int     resultOffset = 0;  /* result may grow, so i+resultOffset
    * is the write location in result */ /* Just copy the first few upperCase characters. */
System.arraycopy(value, offset, result, 0, firstLower); String lang = locale.getLanguage();
boolean localeDependent =
            (lang == "tr" || lang == "az" || lang == "lt");
        char[] upperCharArray;
        int upperChar;
        int srcChar;
        int srcCount;
        for (int i = firstLower; i < count; i += srcCount) {
    srcChar = (int)value[offset+i];
    if ((char)srcChar >= Character.MIN_HIGH_SURROGATE &&
        (char)srcChar <= Character.MAX_HIGH_SURROGATE) {
srcChar = codePointAt(i);
srcCount = Character.charCount(srcChar);
    } else {
        srcCount = 1;
    }
            if (localeDependent) {
                upperChar = ConditionalSpecialCasing.toUpperCaseEx(this, i, locale);
            } else {
                upperChar = Character.toUpperCaseEx(srcChar);
            }
            if ((upperChar == Character.ERROR) ||
                (upperChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
                if (upperChar == Character.ERROR) {
                    if (localeDependent) {
                        upperCharArray =
                            ConditionalSpecialCasing.toUpperCaseCharArray(this, i, locale);
                    } else {
                        upperCharArray = Character.toUpperCaseCharArray(srcChar);
                    }
                } else if (srcCount == 2) {
    resultOffset += Character.toChars(upperChar, result, i + resultOffset) - srcCount;
    continue;
                } else {
                    upperCharArray = Character.toChars(upperChar);
}                /* Grow result if needed */
                int mapLen = upperCharArray.length;
if (mapLen > srcCount) {
                    char[] result2 = new char[result.length + mapLen - srcCount];
                    System.arraycopy(result, 0, result2, 0,
                        i + resultOffset);
                    result = result2;
}
                for (int x=0; x<mapLen; ++x) {
                    result[i+resultOffset+x] = upperCharArray[x];
                }
                resultOffset += (mapLen - srcCount);
            } else {
                result[i+resultOffset] = (char)upperChar;
            }
        }
        return new String(0, count+resultOffset, result);
    }
  且看jdk的stringbuffer的源代码:  public synchronized int lastIndexOf(String str, int fromIndex) {
        return String.lastIndexOf(value, 0, count,
                              str.toCharArray(), 0, str.length(), fromIndex);
    }    /**
     * @since   JDK1.0.2
     */
    public synchronized StringBuffer reverse() {
super.reverse();
return this;
    }    public synchronized String toString() {
return new String(value, 0, count);
    }
这儿方法为什么要用同步,用同步有什么好处,怎么就偏偏要在stringbuffer里面用同步呢?string就没有用。

解决方案 »

  1.   

    if (locale == null) {//偶不明白为什么这儿要判断一下,是否抛出空指针。因为空指针在运行的时候可以由jvm捕获的呀????
            throw new NullPointerException();
            }这个写错了吧,if (locale == null) 
            throw new IllegalArgumentException(locale );
            }
    还差不多
    stringbuffer的同步是为了不同需要嘛,还有个不同步的stringbuffer就是StringBuilder
      

  2.   

    哦,这是JDK的源代码阿,JDK的源代码大多数都是值得学习的,但是这个抛空指针异常就属于脱裤子放屁了。
      

  3.   

    StringBuffer维护同一块内存区域,所以需要同步;而String总会产生多块区域吧。
      

  4.   

    在进入方法后马上判断参数是否符合要求是个很好的习惯。实际上这也不是多此一举,因为参数并不一定在方法开始的地方马上就用到,如果为 null,
    并且不进行参数验证的话,当运行到调用该参数时才会抛出异常,在此之前所有的工作都是
    白作了!如果在开始处进行验证的话,马上就会进行参数验证,不符合要求的参数,下面的
    代码一行都不执行了。
      

  5.   

    拿这个例子来说,如果不进行参数验证的话,这个方法参数要在很后面才会用到:public String toUpperCase(Locale locale) {
        if (locale == null) {
            throw new NullPointerException();
        }    int firstLower;    /* Now check if there are any characters that need to be changed. */
        scan: {
            for (firstLower = 0 ; firstLower < count; ) {
            int c = (int)value[offset+firstLower];
            int srcCount;
            if ((c >= Character.MIN_HIGH_SURROGATE) &&
                (c <= Character.MAX_HIGH_SURROGATE)) {
                c = codePointAt(firstLower);
                srcCount = Character.charCount(c);
            } else {
                srcCount = 1;
            }
            int upperCaseChar = Character.toUpperCaseEx(c);
            if ((upperCaseChar == Character.ERROR) ||
                (c != upperCaseChar)) {
                break scan;
            }
            firstLower += srcCount;
            }
            return this;
        }    char[] result = new char[count]; /* may grow */
        int resultOffset = 0;    /* Just copy the first few upperCase characters. */
        System.arraycopy(value, offset, result, 0, firstLower);    // 到这里才第一次用到,如果 locale 为 null 的话,前面这么一大段都是白做了,代价太大了
        // 希望能理解 Java 类库开发人员为了提高无谓的劳动所做的一切
        String lang = locale.getLanguage();
      

  6.   


    希望楼主不要有这种思想,异常是一种防止错误的机制,JVM 捕捉异常的代价比较高,能想得到的异常尽量自己处理,
    能不让 JVM 处理就不让 JVM 处理。
      

  7.   

    检查参数时必要的,但是抛IllegalArgumentException好一点
      

  8.   

    2, StringBuffer是线程不安全的,想不同步,就用线程安全的StringBuilder。
      

  9.   

    StringBuffer应该是线程安全的,StringBuilder是J2SE5.0才有的,不是线程安全的,是为了在单线程情况下提高效率的。
      

  10.   

    云 线程安全,线程不安全等待之类的并不是我想要的答案,因为这不是本质原因。难道每个工具类的方法都有必要加synchronized吗??????????不要混分了。
      

  11.   

    上面9楼说错了,StringBuffer是线程安全的,StringBuilder才是线程不安全的
    StringBuffer并不是一般我们所说的工具类,它同步目的是为了在多个线程中同时使用时不会出现线程不安全问题。
    而与它功能类似的StringBuilder就是为了只在同一个线程中使用或者不需要考虑线程安全时使用的
      

  12.   

    使用synchronized是为了实现同步机制,同步机制是为了解决对共享资源的访问。是否要加synchronized,是为了解决对共享资源的访问问题。
      

  13.   

    是你自己根本不明白。
    StringBuffer类根本不是工具类,它与String是同等地位的东西。它需要考虑如果被多个线程同时使用时可能出现的问题,所以才加同步
      

  14.   

    受不了了,其他类比如Applet,Thread等好多类为什么他们不加同步,偏偏字符串相关的类要加呢,难道他们就不需要同步了吗????这个怎么解释??????????我还不知道多线程安全什么的
      

  15.   

    我自己的一点推断,java里面两种很特殊的类:
    1,集合类,也有同步的方法,比如hashmap和hashtable。
    2,字符串类。
    他们都有个共同点,那就是内存对这种对象有大小限制。
    字符串,是放在字符串池里面的,这个缓存区域是有限制的,所以就要考虑线程安全。
    比如你stringbuilder的append方法,如果添加太多的字符串,结果会导致内存溢出。
    集合类,当然是装对象的了,如果对象太多了,也会导致内存溢出。
      

  16.   

    因为Thread本身没有东西会出现线程不安全,也就是不存在一种情况 线程A与线程B同时修改Thread本身的属性而导致出现异常的情况
    但是StringBuilder不同,它会修改它内存的成员变量 char value[],如果线程A在append(str)调用过程还没有返回时,线程B同时调用了append(str2),就会导致StringBuilder内部的计算会出现问题,出现append丢失或者错位的问题而StringBuffer增加了同步,保证在线程A的append成功前,线程B不会进入方法,就可以保证两次的添加是正确的,不会出现丢失或者错位等问题、PS:你应该问的是,StringBuffer如果没有同步时会出现怎样的线程不安全问题,这样大家才能理解你的意思!
      

  17.   

    同步不是为了解决内存溢出问题,而是为了解决多个线程同时操作同一个对象时,可能引发的计算错误。像HashMap、ArrayList这些都与StringBuilder类似,同时add或者remove会出现各种问题但是,同步会对性能有影响。所以Java会提供一些不同步的实现类
      

  18.   

    有属性,但是不会出现计算异常。如果只是一个String name的属性,只会出现后面的赋值覆盖了前面的赋值,但是不会出现类似这样的代码: 
    static StringBuilder buff = new StringBuilder(1);
    public static void main(String[] args) throws Exception {
    new Thread() {
    public void run() {
    buff.append("XXXXX");
    }
    }.start();

    buff.append("CC");
    System.out.println(buff);
            }在某种情况下(你可以单步调试使得它必然出现),最后会打印出【CCXXX】,这就出现了append丢失了