Java里使用StringTokenizer进行字符串分割的技巧
Java 里使用 StringTokenizer 进行字符串分割的技巧
StringTokenizer 概述
在 Java 编程中,对字符串进行分割是一项常见的操作。StringTokenizer
类提供了一种方便的方式来将字符串按照特定的分隔符进行分割。它位于 java.util
包中,自 Java 1.0 起就已存在。
StringTokenizer
允许你通过指定一个或多个分隔符来分解字符串。与其他字符串分割方法(如 String.split()
)不同,StringTokenizer
是一个基于枚举(Enumeration
)的方式来处理分割结果,并且在遍历分割后的子字符串时不需要创建数组。
构造函数
StringTokenizer
有多个构造函数,这使得它在不同场景下都能灵活应用。
以默认分隔符构造
StringTokenizer(String str)
这个构造函数使用默认的分隔符集对给定的字符串进行分割。默认的分隔符集是空格、制表符(\t
)、换行符(\n
)和回车符(\r
)。
例如:
String sentence = "Hello world! How are you?";
StringTokenizer tokenizer = new StringTokenizer(sentence);
while (tokenizer.hasMoreTokens()) {
System.out.println(tokenizer.nextToken());
}
在上述代码中,tokenizer
将 sentence
按照默认分隔符进行分割,然后通过 while
循环和 hasMoreTokens()
以及 nextToken()
方法依次输出每个分割后的子字符串。输出结果为:
Hello
world!
How
are
you?
以指定分隔符构造
StringTokenizer(String str, String delim)
此构造函数允许你指定一个分隔符字符串 delim
。字符串 str
将根据 delim
中的字符进行分割。
例如:
String data = "apple,banana;cherry:date";
StringTokenizer tokenizer = new StringTokenizer(data, ",;:.");
while (tokenizer.hasMoreTokens()) {
System.out.println(tokenizer.nextToken());
}
在这段代码中,data
字符串根据 ",;:."
这些分隔符进行分割。输出结果为:
apple
banana
cherry
date
以指定分隔符并控制是否返回分隔符构造
StringTokenizer(String str, String delim, boolean returnDelims)
这个构造函数除了允许指定分隔符外,还通过 returnDelims
参数控制是否将分隔符作为子字符串返回。
如果 returnDelims
为 true
,则分隔符也会被当作子字符串返回。例如:
String data = "apple,banana;cherry:date";
StringTokenizer tokenizer = new StringTokenizer(data, ",;:.", true);
while (tokenizer.hasMoreTokens()) {
System.out.println(tokenizer.nextToken());
}
输出结果为:
apple
,
banana
;
cherry
:
date
如果 returnDelims
为 false
,则分隔符不会被当作子字符串返回,这与第二个构造函数的行为类似。
常用方法
StringTokenizer
类提供了几个关键方法来处理分割后的子字符串。
hasMoreTokens()
boolean hasMoreTokens()
该方法用于检查 StringTokenizer
对象中是否还有更多的子字符串可供获取。如果还有子字符串,则返回 true
,否则返回 false
。
在前面的代码示例中,我们使用 while (tokenizer.hasMoreTokens())
这样的循环结构,就是依赖 hasMoreTokens()
方法来判断是否继续获取下一个子字符串。
nextToken()
String nextToken()
此方法返回 StringTokenizer
对象的下一个子字符串。如果没有更多子字符串,则抛出 NoSuchElementException
。
例如:
String text = "one two three";
StringTokenizer tokenizer = new StringTokenizer(text);
try {
System.out.println(tokenizer.nextToken()); // 输出 "one"
System.out.println(tokenizer.nextToken()); // 输出 "two"
System.out.println(tokenizer.nextToken()); // 输出 "three"
System.out.println(tokenizer.nextToken()); // 抛出 NoSuchElementException
} catch (NoSuchElementException e) {
System.out.println("没有更多子字符串了");
}
countTokens()
int countTokens()
该方法返回 StringTokenizer
对象中剩余的子字符串的数量。注意,这个数量是调用该方法时的即时数量,调用 nextToken()
方法会改变这个数量。
例如:
String text = "a,b,c,d";
StringTokenizer tokenizer = new StringTokenizer(text, ",");
System.out.println("剩余子字符串数量: " + tokenizer.countTokens()); // 输出 4
tokenizer.nextToken();
System.out.println("剩余子字符串数量: " + tokenizer.countTokens()); // 输出 3
StringTokenizer 与 String.split() 的比较
虽然 String.split()
也是用于字符串分割的常用方法,但它与 StringTokenizer
有一些重要的区别。
返回结果类型
String.split()
方法返回一个字符串数组,将所有分割后的子字符串存储在数组中。例如:
String sentence = "Hello world! How are you?";
String[] parts = sentence.split(" ");
for (String part : parts) {
System.out.println(part);
}
而 StringTokenizer
使用枚举(Enumeration
)的方式逐个返回子字符串,不会一次性创建数组,在内存使用上相对更节省,特别是当字符串很长且分割后的子字符串数量很多时。
性能
在性能方面,StringTokenizer
在某些情况下可能比 String.split()
更高效。String.split()
会创建一个数组来存储所有分割后的子字符串,这涉及到数组的创建和内存分配。而 StringTokenizer
按需返回子字符串,避免了一次性创建数组带来的开销。
例如,在处理非常大的字符串时,StringTokenizer
的内存使用会更友好,因为它不需要一次性存储所有分割后的子字符串。
功能灵活性
String.split()
提供了一些高级特性,比如可以使用正则表达式作为分隔符。例如:
String data = "a,123,b,456,c,789";
String[] parts = data.split("\\d+");
for (String part : parts) {
System.out.println(part);
}
在这个例子中,使用正则表达式 \\d+
作为分隔符,将字符串按照连续的数字进行分割。StringTokenizer
则不支持直接使用正则表达式作为分隔符,它只能使用普通的字符序列作为分隔符。
在实际场景中的应用
解析简单配置文件
假设我们有一个简单的配置文件,每一行的格式为 key=value
,并且不同的键值对之间用分号(;
)分隔。我们可以使用 StringTokenizer
来解析这个配置文件。
配置文件内容如下(config.txt):
username=admin;password=123456;server=localhost
Java 代码如下:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.StringTokenizer;
public class ConfigParser {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("config.txt"))) {
String line;
while ((line = br.readLine()) != null) {
StringTokenizer outerTokenizer = new StringTokenizer(line, ";");
while (outerTokenizer.hasMoreTokens()) {
String pair = outerTokenizer.nextToken();
StringTokenizer innerTokenizer = new StringTokenizer(pair, "=");
String key = innerTokenizer.nextToken();
String value = innerTokenizer.nextToken();
System.out.println(key + " : " + value);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在这段代码中,首先使用外层的 StringTokenizer
按照 ;
分割每一行中的键值对,然后使用内层的 StringTokenizer
按照 =
分割每个键值对,从而得到键和值并输出。
处理 CSV 文件数据
CSV(Comma - Separated Values)文件是一种常见的数据存储格式,每行数据由逗号分隔的多个字段组成。
假设我们有一个简单的 CSV 文件(data.csv)内容如下:
John,Doe,30
Jane,Smith,25
我们可以使用 StringTokenizer
来读取并处理这个 CSV 文件的数据。
Java 代码如下:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.StringTokenizer;
public class CSVProcessor {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("data.csv"))) {
String line;
while ((line = br.readLine()) != null) {
StringTokenizer tokenizer = new StringTokenizer(line, ",");
String firstName = tokenizer.nextToken();
String lastName = tokenizer.nextToken();
int age = Integer.parseInt(tokenizer.nextToken());
System.out.println("姓名: " + firstName + " " + lastName + ", 年龄: " + age);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
此代码使用 StringTokenizer
按照逗号分割每一行数据,依次获取名字、姓氏和年龄,并进行相应的处理和输出。
注意事项
空字符串处理
当使用 StringTokenizer
分割字符串时,如果遇到连续的分隔符,StringTokenizer
会跳过中间的空字符串。例如:
String data = "a,,c";
StringTokenizer tokenizer = new StringTokenizer(data, ",");
while (tokenizer.hasMoreTokens()) {
System.out.println(tokenizer.nextToken());
}
输出结果为:
a
c
而 String.split()
方法在这种情况下,如果使用 split(",")
,会返回包含空字符串的数组 ["a", "", "c"]
。如果想要 StringTokenizer
也处理空字符串,可以在构造 StringTokenizer
时将 returnDelims
设置为 true
,然后自行处理分隔符来识别空字符串。
线程安全性
StringTokenizer
不是线程安全的。如果在多线程环境中使用 StringTokenizer
,可能会出现数据不一致的问题。如果需要在多线程环境中进行字符串分割,可以考虑使用线程安全的替代方案,或者对 StringTokenizer
的使用进行适当的同步处理。
例如,可以使用 synchronized
块来确保在多线程环境下 StringTokenizer
的安全使用:
String data = "a,b,c";
StringTokenizer tokenizer = new StringTokenizer(data, ",");
synchronized (tokenizer) {
while (tokenizer.hasMoreTokens()) {
System.out.println(tokenizer.nextToken());
}
}
总结
StringTokenizer
是 Java 中一个方便的字符串分割工具,它在处理简单的字符串分割场景,特别是需要按需获取子字符串而不希望一次性创建数组的情况下,具有一定的优势。与 String.split()
相比,它在内存使用和性能方面可能更适合某些特定的应用场景。然而,在使用 StringTokenizer
时,需要注意其对空字符串的处理方式以及线程安全性问题。通过合理运用 StringTokenizer
,可以更高效地处理字符串分割相关的任务,提高代码的可读性和性能。在实际项目中,应根据具体需求和场景来选择合适的字符串分割方法,无论是 StringTokenizer
还是 String.split()
,亦或是其他第三方库提供的字符串处理工具。