程序中的StringTokenizer和split()有什么区别?

3
我需要将句子中每个单词的首字母大写,并且第一个单词的首字母已经是大写的了,句子只能以句号或问号结尾。然后我还要计算出每个单词中元音字母和辅音字母的数量。
以下是我的代码:
import java.io.*;
import java.util.*;
class ISC_Prac_2015
{
String s;
ISC_Prac_2015()
{
    s="";
}

void input()throws IOException
{
    System.out.println("Enter a sentence :");
    BufferedReader buf=new BufferedReader(new InputStreamReader(System.in));
    s=buf.readLine();
    if(!((s.charAt(s.length()-1)=='.'||s.charAt(s.length()-1)=='?')))
    {
        System.out.println("Invalid input.");
        System.exit(0);
    }
}

char changeToUpper(char c)
{
    return Character.toUpperCase(c);
}

boolean isVowel(char c)
{
    if(c=='a'||c=='e'||c=='i'||c=='o'||c=='u'||c=='A'||c=='E'||c=='I'||c=='O'||c=='U')
        return true;
    else
        return false;
}

void main()throws IOException
{
    input();
    String s2=s.substring(0,s.length()-1);
    StringBuffer s3=new StringBuffer(s2);
    for(int x=0;x<s3.length()-1;x++)
        if(s3.charAt(x)==' ')
            s3.setCharAt(x+1,changeToUpper(s3.charAt(x+1)));
    String s4=s3.toString();
    System.out.println("\n"+s4);
    StringTokenizer st=new StringTokenizer(s4);
    String a[]=new String[st.countTokens()];
    for(int x=0;x<st.countTokens();x++)
    a[x]=st.nextToken();
    /*replace the 4 lines above with String a[]=s4.split(" ");
      and the program works, but why?*/
    System.out.println("Word\t\t"+"Vowels\t\t"+"Consonants");
    int vowel=0,consonant=0;
    for(int x=0;x<a.length;x++)
    {
        for(int y=0;y<a[x].length();y++)
            if(isVowel(a[x].charAt(y)))
                vowel++;
            else
                consonant++;
        if(a[x].length()<8)
            System.out.println(a[x]+"\t\t"+vowel+"\t\t"+consonant);
        else if(a[x].length()>=8&&a[x].length()<16)
            System.out.println(a[x]+"\t"+vowel+"\t\t"+consonant);
        else
            System.out.println(a[x]+vowel+"\t\t"+consonant);
    }
}
}

该类名很奇怪,因为这是我计算机考试中的一个问题。程序有点可以工作,但是在主函数main()的内部for循环中,我出现了空指针异常。但是,当我在程序中使用split(" ")函数时,程序会正确地运行,如我在代码中所注释的那样。但是为什么?难道StringTokenizersplit(" ")不是做同样的事情吗?

1
顺便说一下,你的代码很难阅读,因为缺少空格/大括号和变量名不好(s1s2)。具体是哪一行引发了“NullPointerException”? - ryanyuyu
2个回答

4
StringTokenizer的API文档中countTokens方法的说明如下:
计算此分词器的nextToken方法在生成异常之前可以调用的次数。当前位置不会被提前。
您在for循环内调用它,好像您希望它保持不变,但每次推进到另一个标记时都会减少1。因此,如果您的字符串有4个标记,您只会得到前两个标记。您的字符串数组中留下了null。您可以通过使用调试器或将println添加到代码中来检查此类内容。
有几种解决方案。您可以修复代码以存储标记计数而不是继续调用该方法。更好的办法是hasMoreTokens方法正是为这种情况而设的,请使用它。或者,您可以按照文档中的建议操作:
StringTokenizer是一种遗留类,出于兼容性原因而保留,尽管不鼓励在新代码中使用它。建议任何寻求此功能的人使用String的split方法或java.util.regex包。
请查看文档。当某些内容的行为与您所假定的不同,请仔细检查文档以确定您的假设是否真正有效。

一种解决方法是将初始令牌数量存储到一个变量中,然后在循环条件中使用该变量。 int numTokens = st.countTokens(); for(int x=0; x < numTokens; x++) {//do stuff} - ryanyuyu
1
或者使用while(st.hasMoreTokens)并增加计数器。但是回到问题本身,分词器已经适当地完成了它的工作,NPE是由于结果的使用引起的。@D V - 请记住,默认的分词器设置除了空格以外还有更多的分隔符,这是为了以后的参考。 - Michael

-1

1
但是为什么StringTokenizer会返回null值呢? - Divyanshu Varma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接