java快速学习速查(3)
java快速学习速查(3)
这个部分涉及的方面是循环结构,条件语句,switch case,Number&Math,Character,String,StringBuffer几个方面,对照查询学习
Java循环结构全面解析
循环是编程中控制流程的重要结构,Java提供了多种循环方式以满足不同场景的需求。下面我将系统地讲解Java中的循环结构及其应用。
循环的四大条件:
- 初始化:循环变量的初始值
- 条件判断:循环是否继续执行的条件
- 循环体:每次循环执行的代码块
- 更新:循环变量的变化值
一、循环结构类型
1. while循环
语法结构:1
2
3while (条件表达式) {
// 循环体
}
特点:
- 先判断条件,后执行循环体
- 可能一次都不执行
- 适合不确定循环次数的场景
示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// 计算1-100的和
int sum = 0;
int i = 1;
while (i <= 100) {
sum += i;
i++;
}
System.out.println("Sum: " + sum);
// 读取用户输入直到输入quit
Scanner scanner = new Scanner(System.in);
String input = "";
while (!input.equals("quit")) {
System.out.print("请输入命令:");
input = scanner.nextLine();
System.out.println("你输入了:" + input);
}
2. do-while循环
语法结构:1
2
3do {
// 循环体
} while (条件表达式);
特点:
- 先执行循环体,后判断条件
- 至少执行一次循环体
- 适合需要至少执行一次的场景
示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 密码验证(至少验证一次)
String password;
Scanner scanner = new Scanner(System.in);
do {
System.out.print("请输入密码:");
password = scanner.nextLine();
} while (!password.equals("123456"));
System.out.println("密码正确!");
// 生成随机数直到大于0.9
double randomValue;
do {
randomValue = Math.random();
System.out.println("生成值:" + randomValue);
} while (randomValue <= 0.9);
3. for循环
语法结构:1
2
3for (初始化; 条件表达式; 更新表达式) {
// 循环体
}
特点:
- 循环次数通常已知
- 初始化、条件和更新都在一行
- 适合确定循环次数的场景
示例:1
2
3
4
5
6
7
8
9
10
11
12
13// 打印乘法表
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(j + "×" + i + "=" + (i*j) + "\t");
}
System.out.println();
}
// 遍历数组
int[] numbers = {10, 20, 30, 40, 50};
for (int i = 0; i < numbers.length; i++) {
System.out.println("第" + (i+1) + "个元素:" + numbers[i]);
}
4. 增强for循环(for-each)
语法结构:1
2
3for (元素类型 变量名 : 集合或数组) {
// 循环体
}
特点:
- 简化数组和集合的遍历
- 无需索引变量
- 不能修改原数组/集合元素
示例:1
2
3
4
5
6
7
8
9
10
11// 遍历数组
String[] fruits = {"Apple", "Banana", "Orange"};
for (String fruit : fruits) {
System.out.println(fruit);
}
// 遍历集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
for (int num : numbers) {
System.out.println(num * num);
}
二、循环控制语句
1. break语句
作用: 立即终止当前循环
示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// 查找第一个能被7整除的数
for (int i = 1; i <= 100; i++) {
if (i % 7 == 0) {
System.out.println("找到第一个能被7整除的数:" + i);
break;
}
}
// 多层循环中的break(只跳出最内层循环)
outer: for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (i * j > 6) {
System.out.println("i=" + i + ", j=" + j);
break outer; // 使用标签跳出外层循环
}
}
}
2. continue语句
作用: 跳过本次循环,进入下一次循环
示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 打印1-10的奇数
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue;
}
System.out.println(i);
}
// 跳过空字符串处理
String[] words = {"hello", "", "world", null, "java"};
for (String word : words) {
if (word == null || word.isEmpty()) {
continue;
}
System.out.println(word.toUpperCase());
}
三、循环结构对比
| 特性 | while | do-while | for | for-each |
|---|---|---|---|---|
| 执行顺序 | 先判断后执行 | 先执行后判断 | 先判断后执行 | 自动遍历 |
| 最少执行次数 | 0次 | 1次 | 0次 | 集合大小次 |
| 适用场景 | 条件控制循环 | 至少执行一次 | 固定次数循环 | 集合/数组遍历 |
| 循环变量作用域 | 外部声明 | 外部声明 | 内部声明 | 内部声明 |
| 是否可提前终止 | 是(break) | 是 | 是 | 是 |
四、循环最佳实践
1. 避免无限循环
1 | // 错误示例 |
2. 循环性能优化
1 | // 优化前(每次循环都计算length) |
3. 嵌套循环优化
1 | // 低效的嵌套循环 |
五、典型应用场景
1. 数据处理
1 | // 计算平均值 |
2. 文件读取
1 | // 读取文件所有行 |
3. 游戏循环
1 | boolean gameRunning = true; |
六、常见问题与陷阱
循环条件错误:
1
2// 死循环(i永远不会等于10)
for (int i = 0; i != 10; i += 2) {...}浮点数循环:
1
2
3
4
5
6
7
8// 不可靠的浮点数循环
for (double d = 0.1; d != 1.0; d += 0.1) {...}
// 正确做法
for (int i = 1; i <= 10; i++) {
double d = i * 0.1;
// 使用d
}修改循环变量:
1
2
3
4
5for (int i = 0; i < 10; i++) {
if (i == 5) {
i = 8; // 直接修改循环变量,容易出错
}
}集合遍历时修改:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
for (String s : list) {
if (s.equals("b")) {
list.remove(s); // 抛出ConcurrentModificationException
}
}
// 正确做法:使用迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if (s.equals("b")) {
it.remove(); // 安全删除
}
}Java条件语句全面解析
条件语句是编程中实现分支逻辑的基础结构,Java提供了多种条件语句来实现不同复杂度的判断逻辑。下面我将系统地讲解Java中的条件语句及其应用。
一、基础条件语句
1. 简单if语句
语法结构:1
2
3if (条件表达式) {
// 条件为true时执行的代码
}
示例:1
2
3
4
5
6
7int score = 85;
if (score >= 60) {
System.out.println("及格");
}
// 单行语句可省略大括号(但不推荐)
if (score >= 90) System.out.println("优秀");
2. if-else语句
语法结构:1
2
3
4
5if (条件表达式) {
// 条件为true时执行
} else {
// 条件为false时执行
}
示例:1
2
3
4
5
6int age = 17;
if (age >= 18) {
System.out.println("已成年");
} else {
System.out.println("未成年");
}
3. 多重if-else语句
语法结构:1
2
3
4
5
6
7
8
9if (条件1) {
// 条件1为true时执行
} else if (条件2) {
// 条件2为true时执行
} else if (条件3) {
// 条件3为true时执行
} else {
// 以上条件都不满足时执行
}
示例:1
2
3
4
5
6
7
8
9
10
11
12int score = 78;
if (score >= 90) {
System.out.println("优秀");
} else if (score >= 80) {
System.out.println("良好");
} else if (score >= 70) {
System.out.println("中等");
} else if (score >= 60) {
System.out.println("及格");
} else {
System.out.println("不及格");
}
二、嵌套条件语句
1. 基本嵌套结构
1 | if (条件1) { |
2. 实际应用示例
1 | int age = 20; |
三、特殊条件表达式
1. 三元运算符
语法结构:1
变量 = (条件) ? 表达式1 : 表达式2;
示例:1
2
3
4int a = 10, b = 20;
int max = (a > b) ? a : b;
String result = (score >= 60) ? "及格" : "不及格";
2. switch-case语句
语法结构:1
2
3
4
5
6
7
8
9
10
11switch (表达式) {
case 值1:
// 代码
break;
case 值2:
// 代码
break;
...
default:
// 默认代码
}
示例:1
2
3
4
5
6
7
8
9
10
11
12
13int day = 3;
String dayName;
switch (day) {
case 1: dayName = "星期一"; break;
case 2: dayName = "星期二"; break;
case 3: dayName = "星期三"; break;
case 4: dayName = "星期四"; break;
case 5: dayName = "星期五"; break;
case 6: dayName = "星期六"; break;
case 7: dayName = "星期日"; break;
default: dayName = "无效日期";
}
System.out.println(dayName);
Java 12+增强switch:1
2
3
4
5
6
7
8
9
10String dayName = switch (day) {
case 1 -> "星期一";
case 2 -> "星期二";
case 3 -> "星期三";
case 4 -> "星期四";
case 5 -> "星期五";
case 6 -> "星期六";
case 7 -> "星期日";
default -> "无效日期";
};
四、条件语句最佳实践
1. 代码风格建议
1 | // 推荐:清晰的缩进和括号 |
2. 条件表达式优化
1 | // 不推荐:嵌套过深 |
3. 提前返回模式
1 | // 不推荐:多层嵌套 |
五、常见问题与陷阱
1. 浮点数比较
1 | // 错误方式 |
2. 空指针异常
1 | String str = null; |
3. switch语句注意点
1 | int num = 2; |
六、实际应用案例
1. 登录验证
1 | public void login(String username, String password) { |
2. 成绩等级判断
1 | char determineGrade(int score) { |
3. 月份天数判断
1 | int getDaysInMonth(int year, int month) { |
Java switch-case 语句全面解析
switch-case 是Java中用于多分支选择的结构,比多重if-else语句更加清晰易读。下面我将详细讲解switch-case的各种用法和特性。
一、基本语法结构
1 | switch (表达式) { |
二、switch语句特性
1. 支持的数据类型
- Java 7之前:byte, short, int, char
- Java 7+:新增String类型
- Java 14+:支持表达式形式(预览特性)
2. 执行流程
- 计算表达式的值
- 与case标签的值比较
- 匹配成功后执行对应的代码块
- 遇到break或执行到switch末尾时退出
3. break的重要性
1 | int day = 2; |
三、完整使用示例
1. 传统写法
1 | public class DayOfWeek { |
2. 多个case合并
1 | int month = 2; |
3. 字符串匹配(Java 7+)
1 | String fruit = "Apple"; |
四、Java 12+ 新特性
1. 箭头语法(->)
1 | int day = 3; |
2. yield返回值(Java 13+)
1 | String season = switch (month) { |
五、最佳实践
- 总是包含default分支:处理未预期的值
- 不要省略break:除非有意使用fall-through特性
- 保持case分支简洁:复杂逻辑应提取为方法
- 利用多case合并:简化相同处理的case
- 考虑使用枚举:提高类型安全性
六、与if-else对比
| 特性 | switch-case | if-else |
|---|---|---|
| 可读性 | 多分支时更清晰 | 分支多时难以阅读 |
| 性能 | 通常使用跳转表更高效 | 需要顺序比较 |
| 表达式类型 | 有限支持 | 支持任何布尔表达式 |
| 适用场景 | 离散值精确匹配 | 范围判断或复杂条件 |
七、常见问题
忘记break导致意外fall-through
1
2
3
4
5// 错误示例
switch (x) {
case 1: System.out.println("1"); // 忘记break
case 2: System.out.println("2"); break;
}case值重复
1
2
3
4switch (x) {
case 1: ... break;
case 1: ... break; // 编译错误:重复的case
}使用null导致NPE
1
2String s = null;
switch (s) { ... } // 抛出NullPointerException类型不匹配
1
2long x = 10;
switch (x) { ... } // 编译错误:不支持long类型Java Number & Math 类全面解析
Java 提供了强大的数字处理能力,包括基本数据类型的包装类和丰富的数学运算工具。下面我将系统地讲解这些功能的使用方法和最佳实践。
一、Number 包装类体系
1. 包装类与基本类型对应关系
| 基本类型 | 包装类 | 继承关系 |
|---|---|---|
| byte | Byte | → Number → Object |
| short | Short | → Number → Object |
| int | Integer | → Number → Object |
| long | Long | → Number → Object |
| float | Float | → Number → Object |
| double | Double | → Number → Object |
| char | Character | → Object |
| boolean | Boolean | → Object |
2. 自动装箱与拆箱
1 | // 自动装箱 |
3. 常用方法示例
1 | // 字符串转换 |
二、Math 数学工具类
1. 基本数学运算
1 | // 绝对值 |
2. 指数与对数
1 | // 幂运算 |
3. 三角函数
1 | // 角度转弧度 |
4. 随机数生成
Random类
Java.util.Random 用于产生随机数
1 | // 生成[0,1)之间的随机double |
三、数值处理高级技巧
1. 精确计算问题
1 | // 浮点数精度问题 |
2. 数值溢出处理
1 | // 整数溢出 |
3. 位运算操作
1 | // 基本位运算 |
四、Java 8+ 新增数值API
1. 无符号数支持
1 | // 无符号比较 |
2. 数值溢出检查
1 | // 安全运算方法 |
3. 数学增强方法
1 | // 精确数学运算 |
五、最佳实践与性能考虑
优先使用基本类型:包装类有额外开销
1
2
3
4
5
6
7
8
9
10
11// 不好
Integer sum = 0;
for (int i = 0; i < 100; i++) {
sum += i; // 反复装箱拆箱
}
// 好
int sum = 0;
for (int i = 0; i < 100; i++) {
sum += i;
}缓存机制利用:
1
2
3
4
5
6
7Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true (使用缓存)
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false (超出缓存范围)精确计算选择:
1
2
3
4// 金融计算使用BigDecimal
BigDecimal price = new BigDecimal("19.99");
BigDecimal quantity = new BigDecimal("2.5");
BigDecimal total = price.multiply(quantity).setScale(2, RoundingMode.HALF_UP);数学函数优化:
1
2
3// 重复计算先缓存
double sinValue = Math.sin(angle);
double cosValue = Math.cos(angle);记住在关键性能路径上避免不必要的对象创建,并注意数值精度和溢出问题。
Java Character 类全面解析
Character 类是 Java 中用于操作单个字符的包装类,提供了丰富的字符操作方法。下面我将系统地讲解 Character 类的各种功能和使用场景。
一、Character 类基础
1. 创建 Character 对象
1 | // 构造函数方式(Java 9后已废弃) |
2. 基本方法
1 | char c = 'a'; |
二、字符类型检测方法
1. 常用检测方法
| 方法名 | 描述 | 示例 |
|---|---|---|
isLetter(char ch) |
判断是否是字母 | isLetter('A') → true |
isDigit(char ch) |
判断是否是数字 | isDigit('5') → true |
isLetterOrDigit(char) |
判断是否是字母或数字 | isLetterOrDigit('_') → false |
isWhitespace(char) |
判断是否是空白字符 | isWhitespace('\t') → true |
isUpperCase(char) |
判断是否是大写字母 | isUpperCase('A') → true |
isLowerCase(char) |
判断是否是小写字母 | isLowerCase('a') → true |
2. Unicode 相关检测
1 | // 判断是否是Java标识符起始字符 |
三、字符转换操作
1. 大小写转换
1 | // 单个字符转换 |
2. 数字字符转换
1 | // 字符数字转数值 |
3. 字符与Unicode
1 | // 获取Unicode代码点 |
四、特殊字符处理
1. 转义字符
| 转义序列 | Unicode | 描述 |
|---|---|---|
\t |
\u0009 | 水平制表符 |
\b |
\u0008 | 退格 |
\n |
\u000a | 换行 |
\r |
\u000d | 回车 |
\f |
\u000c | 换页 |
\' |
\u0027 | 单引号 |
\" |
\u0022 | 双引号 |
\\ |
\u005c | 反斜杠 |
2. Unicode 处理
1 | // 直接使用Unicode |
五、Character 常量
Character 类提供了许多有用的常量:
1 | // 基本类型大小 |
六、实际应用示例
1. 统计字符串中的字母和数字
1 | public class CharCounter { |
2. 密码强度验证
1 | public class PasswordValidator { |
3. 驼峰命名转换
1 | public class CamelCaseConverter { |
七、性能考虑与最佳实践
避免不必要的装箱:
1
2
3
4
5
6
7// 不好
Character ch = 'a';
if (ch.equals('b')) {...}
// 好
char c = 'a';
if (c == 'b') {...}使用String处理字符串:
1
2
3
4
5
6// 不要这样处理字符串
Character[] chars = ...;
// 应该使用String或char[]
String str = ...;
char[] chars = ...;处理代理对:
1
2
3
4
5
6String emoji = "😀";
// 错误方式(会拆分成两个char)
char first = emoji.charAt(0); // '\uD83D'
// 正确方式(处理代码点)
int codePoint = emoji.codePointAt(0); // 128512使用Character常量:
1
2
3
4
5
6
7// 不要使用魔法值
if (c == 9) {...}
// 使用预定义常量
if (c == '\t') {...}
// 或
if (c == Character.TAB) {...}
通过合理使用 Character 类,可以高效地处理各种字符操作需求,特别是在文本处理、输入验证和国际化应用中。记住在性能敏感的场景中优先使用基本类型 char,并注意 Unicode 特殊字符的处理。
Java String 类全面解析
String 类是 Java 中最常用的类之一,用于表示和操作文本数据。下面我将系统地讲解 String 类的各种功能和使用场景。
Java.lang.String 类代表字符串,java程序中所有的字符串都作为此类的实例,字符串是常量,他们的值在创建之后是不能更改的。
从源码可以看到,String是被final修饰的,并且底层使用char数组实现。
一、String 类基础
1. 创建 String 对象
1 | // 字面量方式(推荐) |
2. 字符串池与内存管理
字符串池:
字符串常量是JVM(java虚拟机)中的一个特殊存储区域,用于存储字符串常量。当使用字面量方式创建String对象时,JVM会首先检查字符串常量池是否已经存在相同内容的字符串对象,如果存在,则直接返回常量池中该字符串对象的引用,如果不存在,则在常量池中创建一个新的字符串对象,并返回其
引用。
堆内存:
- 用于存储对象实例,包括字符串对象
- 当使用
new关键字创建字符串对象时,会在堆上分配内存
栈内存:
- 用于存储基本数据类型和引用变量
- 栈内存的分配和释放速度快,仅次于寄存器
- 栈内存的大小通常是固定的,无法动态扩展
- 栈内存的存储内容包括局部变量、方法参数、方法调用信息等
1 | String s1 = "Java"; // 存储在字符串常量池 |
字符串常见的几种创建方式1
2
3
4
5
6
7
8
9
10
11
12 public class Test3 {
public static void main(String[] args) {
// 1.通过字面量直接赋值方式创建对象是存放在方法区的常量池
String str="helloWorld";
// 2.通过构造方法创建字符串,字符串对象是在堆内中
String str1=new String("helloWorld");
// 3.方式三
char []c={'a','b','c'};
String str2=new String(c);
String str3=new String(c,0,c.length);
}
}
注意
java中的”==”操作符的作用:
- 基本数据类型:比较的是内容
- 引用数据类型:比较的是对象的内存对象。
二、字符串基本操作
1. 获取字符串信息
1 | String str = "Hello World"; |
字符串获取方法补充1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28public static void main(String[] args) {
String s="hello World";
// 获取字符串的长度,其实就是字符串的字符个数
System.out.println(s.length());
// charAt()获取指定索引处的字符
System.out.println(s.charAt(2));
// trim()去掉字符串(左右)前后(不包括里面的)的空格
System.out.println(s.trim().length());
// replace("字符串","新字符") 替换
System.out.println(s.replace(" ","-"));
// substring(开始索引) 索引从0开始获取子串, 直到末尾
System.out.println(s.substring(3));
// substring(开始索引,结束索引) 包括开始,不包括结束
System.out.println(s.substring(3,7));
// concat() 字符串拼接
System.out.println(s.concat("2025!!"));
// 判断字符串里面是否包含特定的字符
if(s.contains("e")){
System.out.println("包含e");
}
// String.valueOf() 将各种类型转换成字符串
System.out.println(String.valueOf(123));
System.out.println(String.valueOf(true));
// 此方法同等String.valueOf(123)
// 字符串+基本数据类型 变成字符串
System.out.println(""+123);
System.out.println(345+"");
}
面试题:
equals和==的区别?
- == 是运算符,如果是基本数据类型,比较的存储的值,如果是引用数据类型,则比较所指对象的地址值。
- String类重写Object类的equals()方法,用于比较两个字符串的内容是否相等。
严重注意事项
字符串数组创建的时候每个元素默认是null,所以这个是个大地雷,经常会因为这个原因导致空指针异常(NullPointerException)。
你可以看下面这个例子:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public class Tset07 {
public static void main(String[] args) {
String[] arr = new String[10];
arr[0] = "java";
arr[1] = "linux";
arr[2] = "mysql";
//遍历字符串数组,打印每个字符长度
for (int i = 0; i < arr.length; i++) {
//人畜无害是吧
//可以通过编译
//运行时就是个大地雷
//这是因为字符串数组默认创建时全都是null,在这里除了前三个都是null,遍历过前三个就爆炸了
//所以我们在对字符串数组进行操作的时候必须进行非空判断,防止空指针异常
System.out.println(arr[i].length());
}
}
}
所以我们在使用字符串数组和字符串的时候,必须要进行非空判断,防止空指针异常。
同时,栈溢出问题也不容小看,这些玩意不会给我吗进行代码提示
2. 字符串比较
| 方法名 | 描述 | 示例 |
|---|---|---|
equals(Object obj) |
比较内容是否相同 | "abc".equals("abc") → true |
equalsIgnoreCase(String) |
忽略大小写比较内容 | "ABC".equalsIgnoreCase("abc") → true |
compareTo(String) |
按字典顺序比较 | "a".compareTo("b") → -1 |
compareToIgnoreCase(String) |
忽略大小写的字典顺序比较 | "A".compareToIgnoreCase("a") → 0 |
startsWith(String) |
检查是否以指定字符串开头 | "Hello".startsWith("He") → true |
endsWith(String) |
检查是否以指定字符串结尾 | "Hello".endsWith("lo") → true |
三、字符串操作与转换
1. 字符串连接
1 | // 使用 + 运算符 |
2. 字符串修改
1 | String original = "Java Programming"; |
3. 大小写转换
1 | String str = "Hello World"; |
四、字符串格式化
1. 静态 format 方法
这个方法用于格式化字符串,将指定的参数按照格式说明符替换到字符串中。1
2
3
4
5
6
7String name = "Alice";
int age = 25;
double score = 95.5;
// 格式化字符串
String info = String.format("Name: %s, Age: %d, Score: %.2f", name, age, score);
// "Name: Alice, Age: 25, Score: 95.50"
2. 常用格式说明符
| 说明符 | 适用类型 | 示例输出 |
|---|---|---|
%s |
字符串 | “Hello” |
%d |
十进制整数 | 123 |
%f |
浮点数 | 3.141593 |
%.2f |
保留两位小数 | 3.14 |
%c |
字符 | ‘A’ |
%b |
布尔值 | true |
%n |
平台相关的行分隔符 | (换行) |
五、字符串分割与正则表达式
1. 字符串分割
1 | String str = "apple,orange,banana,grape"; |
2. 正则表达式匹配
1 | String email = "test@example.com"; |
六、字符串与字符/字节数组转换
1. 字符数组转换
1 | String str = "Hello"; |
2. 字节数组转换
1 | String str = "Hello"; |
七、实际应用示例
前提提要,这毕竟是用来查找的学习笔记,所以常用的函数和方法我就放在这里了,稍微有点多就是了,我会把最最最常用的给标出来,放心吧。
String 类常用函数
函数名称 功能描述 使用方式示例 注意事项 == length()==获取字符串的字符长度 String str = "hello"; int len = str.length();(结果:5)1. 区分数组的 length(属性)和字符串的length()(方法)
2. 空字符串""的长度为0,null调用该方法会抛空指针异常charAt(int index)获取指定索引位置的字符 String str = "hello"; char c = str.charAt(1);(结果:’e’)1. 索引从0开始
2. 索引超出范围会抛出IndexOutOfBoundsExceptionequals(Object obj)比较两个字符串的内容是否完全相同 String str1 = "hello"; String str2 = "HELLO"; boolean b = str1.equals(str2);(结果:false)1. 区分大小写
2. 避免空指针:建议用非空字符串调用,如"hello".equals(str)equalsIgnoreCase(String anotherString)忽略大小写比较字符串内容 String str1 = "hello"; String str2 = "HELLO"; boolean b = str1.equalsIgnoreCase(str2);(结果:true)仅忽略英文字母大小写,其他字符(如数字、符号)严格匹配 contains(CharSequence s)判断字符串是否包含指定子串 String str = "hello world"; boolean b = str.contains("world");(结果:true)参数可以是String、StringBuffer、StringBuilder等CharSequence类型 indexOf(String str)查找子串首次出现的索引,未找到返回-1 String str = "hello world"; int idx = str.indexOf("o");(结果:4)1. 索引从0开始
2. 支持重载:indexOf(str, int fromIndex)(从指定位置开始查找)lastIndexOf(String str)查找子串最后一次出现的索引,未找到返回-1 String str = "hello world"; int idx = str.lastIndexOf("o");(结果:7)支持重载: lastIndexOf(str, int fromIndex)(从指定位置向前查找)substring(int beginIndex)截取从指定索引到末尾的子串 String str = "hello world"; String sub = str.substring(6);(结果:”world”)1. 索引从0开始
2. 重载方法substring(beginIndex, endIndex):包含begin,不包含endtrim()去除字符串首尾的空白字符(空格、制表符、换行等) String str = " hello "; String res = str.trim();(结果:”hello”)1. Java 11前仅去除ASCII空白符,Java 11+可使用 strip()(支持Unicode空白)
2. 不改变原字符串内容replace(CharSequence oldStr, CharSequence newStr)替换字符串中所有指定的子串 String str = "hello world"; String res = str.replace("o", "0");(结果:”hell0 w0rld”)1. 替换所有匹配项
2. 区分大小写,如需忽略大小写可使用replaceAll()结合正则split(String regex)按指定正则表达式分割字符串,返回字符串数组 String str = "a,b,c"; String[] arr = str.split(",");(结果:[“a”,”b”,”c”])1. 参数是正则表达式,特殊字符(如.、 、*)需转义( \\.)
2. 分割空字符串可能返回长度为1的数组(包含空串)toUpperCase()将字符串所有字符转为大写 String str = "hello"; String res = str.toUpperCase();(结果:”HELLO”)遵循系统默认Locale,如需指定Locale可使用重载方法 toLowerCase()将字符串所有字符转为小写 String str = "HELLO"; String res = str.toLowerCase();(结果:”hello”)同上,避免因Locale差异导致转换异常 isEmpty()判断字符串是否为空(长度为0) String str = ""; boolean b = str.isEmpty();(结果:true)1. null调用该方法会抛空指针异常
2. 可结合str == null判断:`str == nullstr.isEmpty()` startsWith(String prefix)判断字符串是否以指定前缀开头 String str = "hello"; boolean b = str.startsWith("he");(结果:true)重载方法 startsWith(prefix, int offset):从指定索引开始判断前缀endsWith(String suffix)判断字符串是否以指定后缀结尾 String str = "hello"; boolean b = str.endsWith("lo");(结果:true)区分大小写,无忽略大小写的重载方法,需自行转换后判断 valueOf(Object obj)静态方法,将任意类型转为字符串 int num = 123; String str = String.valueOf(num);(结果:”123”)1. 若obj为null,返回字符串”null”
2. 比obj.toString()更安全,避免空指针
String 类核心要点
String是不可变字符串,所有修改操作都会返回新对象,原对象不变;- 空指针防护:调用
equals()、length()等方法前,需确保字符串非null; - 正则相关方法(如
split()、replaceAll())需注意特殊字符转义。
1. 字符串反转
1 | public class StringReverse { |
2. 检查回文字符串
1 | public class PalindromeChecker { |
3. 统计单词出现次数
1 | import java.util.HashMap; |
八、性能考虑与最佳实践
字符串拼接性能:
1
2
3
4
5
6
7
8
9
10
11
12// 不好 - 创建多个临时对象
String result = "";
for (int i = 0; i < 100; i++) {
result += i;
}
// 好 - 使用StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100; i++) {
sb.append(i);
}
String result = sb.toString();字符串比较:
1
2
3
4
5
6
7
8// 不好 - 可能NullPointerException
if (str.equals("literal")) {...}
// 好 - 避免NPE
if ("literal".equals(str)) {...}
// 更好 - Java 7+
if (Objects.equals(str, "literal")) {...}字符串常量池利用:
1
2
3
4
5// 不好 - 创建不必要的对象
String str = new String("literal");
// 好 - 利用字符串常量池
String str = "literal";处理大文本:
1
2
3
4
5
6
7// 对于大文件处理,避免一次性加载到内存
try (BufferedReader reader = new BufferedReader(new FileReader("large.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
// 处理每行
}
}国际化考虑:
1
2
3// 指定Locale进行大小写转换
String lower = str.toLowerCase(Locale.ENGLISH);
String upper = str.toUpperCase(Locale.FRENCH);
通过合理使用 String 类及其相关工具类,可以高效地处理各种文本操作需求。记住字符串是不可变对象,在需要频繁修改字符串的场景中应考虑使用 StringBuilder 或 StringBuffer。
Java StringBuffer 和 StringBuilder 类全面解析
由于String是字符串是常量,他们的值在创建之后不能更改,如果我们使用这个String频繁进行操作,会有性能问题,这个时候需要使用StringBuffer和StringBuilder类,StringBuffer也被叫做“字符串缓冲区”,以后如果遇到什么缓冲,缓存,第一反应是为了提供性能。
在使用StringBuffer类时,每次都会对StringBuffer对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用StringBuffer,StringBuilder类在java5被提出的,StringBuilder和
StringBuffer之间的最大不同是在于StringBuilder的方法不是线程安全
操作完String以后返回的是另外一个新的对象
一、StringBuffer 和 StringBuilder 基础
1. 创建对象
1 | // StringBuilder 创建 |
2. 主要区别
| 特性 | StringBuilder | StringBuffer |
|---|---|---|
| 线程安全 | 非线程安全 | 线程安全 |
| 性能 | 更高 | 稍低 |
| 引入版本 | Java 5 | Java 1.0 |
| 适用场景 | 单线程环境 | 多线程环境 |
面试题:String/Stringbuffer/StringBuilder的区别?
1.String字符串的值不可改变,导致每次对String操作都会生成新的String对象,这样不仅效率底下,而且大量浪费有限的内存空间。如果频繁对字符型修改推荐使用StringBuffer和StringBuilder
2.StringBuffer是线程安全的,而StringBuilder是线程不安全的,在不考虑线程安全的情况下
3.StringBuilder的运行效率比StringBuffer更高。
二、常用方法详解
1. 追加内容 (append)
StringBuffer类的append()方法源码
注意代码不需要考虑线程安全问题的情况下,首先考虑使用StringBuilder。
1 |
|
1 | StringBuilder sb = new StringBuilder("Hello"); |
2. 插入内容 (insert)
1 | StringBuilder sb = new StringBuilder("HelloWorld"); |
3. 删除内容 (delete)
1 | StringBuilder sb = new StringBuilder("HelloJavaWorld"); |
4. 替换内容 (replace)
1 | StringBuilder sb = new StringBuilder("HelloWorld"); |
5. 反转字符串 (reverse)
1 | StringBuilder sb = new StringBuilder("Hello"); |
三、容量管理
1. 容量相关方法
1 | StringBuilder sb = new StringBuilder(50); // 初始容量50 |
2. 容量增长机制
当追加内容超过当前容量时,会自动扩容:
- 新容量 = (原容量 + 1) * 2
- 如果还不够,则直接扩容到所需大小
1 | StringBuilder sb = new StringBuilder(); // 默认容量16 |
四、字符串操作
1. 获取子串和字符
1 | StringBuilder sb = new StringBuilder("HelloWorld"); |
2. 查找操作
1 | StringBuilder sb = new StringBuilder("HelloHello"); |
五、实际应用示例
StringBuffer & StringBuilder 常用函数
说明
StringBuffer:线程安全,效率较低,适用于多线程场景StringBuilder:非线程安全,效率较高,适用于单线程场景- 两者方法名和功能完全一致,示例以
StringBuilder为例
| 函数名称 | 功能描述 | 使用方式示例 | 注意事项 |
|---|---|---|---|
append(任意类型) |
将任意类型数据追加到字符串末尾 | StringBuilder sb = new StringBuilder("hello"); sb.append(" world");(结果:”hello world”) |
1. 支持所有基本类型、对象(调用toString())2. 直接修改原对象,无返回新对象(区别于String) |
insert(int offset, 任意类型) |
在指定索引位置插入数据 | StringBuilder sb = new StringBuilder("hello"); sb.insert(2, "xx");(结果:”hexxllo”) |
1. 索引从0开始,超出范围抛IndexOutOfBoundsException2. 插入位置为0则在开头插入,为长度则等价于append |
delete(int start, int end) |
删除指定索引范围的字符(包含start,不包含end) | StringBuilder sb = new StringBuilder("hello"); sb.delete(1, 3);(结果:”hlo”) |
索引超出范围会抛异常,deleteCharAt(int index)可删除单个字符 |
replace(int start, int end, String str) |
替换指定索引范围的字符为目标字符串 | StringBuilder sb = new StringBuilder("hello"); sb.replace(1, 3, "xx");(结果:”hxxlo”) |
1. 范围是[start, end) 2. 目标字符串长度可与原范围长度不同 |
reverse() |
反转字符串内容 | StringBuilder sb = new StringBuilder("hello"); sb.reverse();(结果:”olleh”) |
直接修改原对象,无返回新对象 |
charAt(int index) |
获取指定索引位置的字符 | StringBuilder sb = new StringBuilder("hello"); char c = sb.charAt(1);(结果:’e’) |
与String的charAt()规则一致,索引从0开始 |
setCharAt(int index, char ch) |
修改指定索引位置的字符 | StringBuilder sb = new StringBuilder("hello"); sb.setCharAt(1, 'E');(结果:”hEllo”) |
1. 索引超出范围抛异常 2. 仅能修改单个字符,区别于replace |
length() |
获取字符序列的长度 | StringBuilder sb = new StringBuilder("hello"); int len = sb.length();(结果:5) |
与String的length()用法一致 |
capacity() |
获取当前缓冲区的容量(可存储字符数,大于等于length) | StringBuilder sb = new StringBuilder(); int cap = sb.capacity();(默认:16) |
1. 初始容量:空构造器为16,带字符串构造器为16 + 字符串长度2. 容量不足时会自动扩容(通常翻倍+2) |
ensureCapacity(int minimumCapacity) |
手动指定最小容量,避免频繁扩容 | StringBuilder sb = new StringBuilder(); sb.ensureCapacity(100); |
仅当当前容量小于指定值时扩容,否则无操作 |
trimToSize() |
收缩容量至当前字符长度,节省内存 | StringBuilder sb = new StringBuilder("hello"); sb.trimToSize(); |
扩容后的缓冲区若有空闲空间,调用后会释放 |
substring(int start) |
截取子串(返回String类型) | StringBuilder sb = new StringBuilder("hello"); String sub = sb.substring(2);(结果:”llo”) |
1. 重载方法substring(start, end)规则同String2. 返回新的String对象,不修改原StringBuilder |
toString() |
将StringBuilder/StringBuffer转为String类型 | StringBuilder sb = new StringBuilder("hello"); String str = sb.toString(); |
是两者与String互转的核心方法,转换后不可变 |
StringBuffer/StringBuilder 核心要点
- 两者是可变字符序列,修改操作直接作用于原对象,效率远高于String;
- 线程安全选
StringBuffer,单线程高性能选StringBuilder; - 初始容量可根据业务预估设置,减少自动扩容带来的性能损耗。
1. 高效字符串拼接
1 | public class StringConcatenation { |
2. SQL 查询构建
1 | public class SqlBuilder { |
3. CSV 文件生成
1 | public class CsvGenerator { |
六、性能考虑与最佳实践
选择正确的类:
1
2
3
4
5// 单线程环境 - 使用StringBuilder
StringBuilder sb = new StringBuilder();
// 多线程环境 - 使用StringBuffer
StringBuffer sbf = new StringBuffer();初始化容量:
1
2// 如果知道大概大小,预先设置容量
StringBuilder sb = new StringBuilder(1024); // 避免频繁扩容链式调用:
1
2
3
4
5
6// 使用方法链提高可读性
String result = new StringBuilder()
.append("Name: ").append(name)
.append(", Age: ").append(age)
.append(", Score: ").append(score)
.toString();与String的转换:
1
2
3
4// 只在需要时才转换为String
StringBuilder sb = new StringBuilder();
// ...多次操作...
String finalString = sb.toString(); // 最后转换线程安全考虑:
1
2
3
4
5
6
7
8// 在多线程环境中使用StringBuffer
StringBuffer sharedBuffer = new StringBuffer();
// 或者使用同步包装
StringBuilder sb = new StringBuilder();
synchronized(sb) {
sb.append("thread-safe operation");
}避免不必要的使用:
1
2
3
4
5
6
7
8// 简单拼接不需要StringBuilder
String simple = "Hello " + name; // 编译器会自动优化
// 循环中应该使用StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100; i++) {
sb.append(i);
}
通过合理使用 StringBuffer 和 StringBuilder,可以显著提高字符串处理性能,特别是在需要频繁修改字符串内容的场景中。根据线程安全需求选择合适的类,并注意容量管理和转换时机,以获得最佳性能。
