1. Java基础语法精要
1.1 变量与数据类型实战
Java作为强类型语言,变量声明时必须显式指定数据类型。在今天的实操中发现,整型变量使用int声明时,如果赋值超过2147483647这个临界值,编译器会直接报错。这时候就需要改用long类型,记得在数值后加L后缀:
java复制long population = 7900000000L; // 全球人口数需要long类型存储
浮点数的精度问题特别值得注意。测试时发现用double计算0.1+0.2居然得到0.30000000000000004,这是因为二进制浮点数无法精确表示十进制小数。金融计算一定要用BigDecimal:
java复制BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
System.out.println(a.add(b)); // 精确输出0.3
1.2 运算符的隐藏特性
三目运算符的嵌套使用容易产生歧义。今天调试时遇到个典型问题:
java复制int x = 10;
int y = x > 5 ? x < 15 ? 100 : 200 : 300;
这个表达式实际等价于 x > 5 ? (x < 15 ? 100 : 200) : 300,最终y的值是100。建议嵌套超过两层时就改用if-else结构,可读性更好。
位运算在权限控制等场景非常高效。比如用二进制位表示读写执行权限:
java复制final int READ = 1 << 0; // 0001
final int WRITE = 1 << 1; // 0010
final int EXEC = 1 << 2; // 0100
int userPermission = READ | WRITE; // 0011表示有读写权限
2. 流程控制深度解析
2.1 switch的进化之路
从Java 12开始,switch表达式可以返回值了,而且支持箭头语法。今天尝试了新写法:
java复制String dayType = switch (day) {
case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" -> "Weekday";
case "Saturday", "Sunday" -> "Weekend";
default -> throw new IllegalArgumentException("Invalid day: " + day);
};
重要提示:使用switch表达式时必须穷举所有可能情况,或者添加default分支,否则编译不通过。
2.2 循环优化的三个段位
- 青铜段位:基础for循环
java复制for (int i = 0; i < 10; i++) {
System.out.println(i);
}
- 白银段位:增强for循环
java复制int[] numbers = {1, 2, 3};
for (int num : numbers) {
System.out.println(num);
}
- 王者段位:流式处理(Java8+)
java复制Arrays.stream(numbers)
.filter(n -> n % 2 == 0)
.forEach(System.out::println);
实测在10万次循环测试中,传统for循环比增强for循环快约15%,但代码可读性较差。建议在性能敏感场景用传统for,日常开发用增强for。
3. 数组操作的黑科技
3.1 数组初始化的五种姿势
- 标准初始化
java复制int[] arr1 = new int[3];
- 直接赋值
java复制int[] arr2 = {1, 2, 3};
- 匿名数组
java复制new int[]{1, 2, 3};
- 使用Arrays工具类
java复制int[] arr4 = Arrays.copyOf(arr2, arr2.length);
- 流式生成(Java8+)
java复制int[] arr5 = IntStream.range(1, 4).toArray();
3.2 二维数组的陷阱
声明二维数组时,第一个中括号必须有长度,第二个可以留空:
java复制int[][] matrix = new int[3][]; // 正确
int[][] wrong = new int[][3]; // 编译错误
锯齿数组的实际应用:存储不同长度的数据行
java复制int[][] jagged = {
{1},
{2, 3},
{4, 5, 6}
};
4. 方法设计的艺术
4.1 参数传递的真相
Java总是值传递!今天用三个案例验证了这个结论:
案例1:基本类型传值
java复制void change(int x) { x = 100; }
int num = 50;
change(num);
System.out.println(num); // 输出50,未改变
案例2:对象引用传值
java复制void changeName(Person p) { p.setName("New"); }
Person person = new Person("Old");
changeName(person);
System.out.println(person.getName()); // 输出New
案例3:试图改变引用本身
java复制void changeRef(Person p) { p = new Person("New"); }
Person person = new Person("Old");
changeRef(person);
System.out.println(person.getName()); // 输出Old
4.2 可变参数的秘密
可变参数实际上是数组的语法糖。有几个注意事项:
- 一个方法只能有一个可变参数
- 必须是最后一个参数
- 可以传数组或离散值
java复制void printAll(String... items) {
for (String item : items) {
System.out.println(item);
}
}
printAll("A", "B", "C"); // 离散值
printAll(new String[]{"X", "Y"}); // 数组
5. 调试技巧实录
5.1 断点调试三剑客
- 条件断点:右键断点 -> 设置条件
- 异常断点:Debug视图 -> 添加Java异常断点
- 方法断点:直接在方法声明行打断点
5.2 日志调试法
推荐使用SLF4J+Logback组合:
java复制import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Demo {
private static final Logger logger = LoggerFactory.getLogger(Demo.class);
public static void main(String[] args) {
logger.debug("调试信息");
logger.info("普通信息");
logger.error("错误信息", new Exception("测试异常"));
}
}
配置logback.xml控制输出级别和格式,比System.out.println专业得多。
6. 每日编码规范
- 类名使用大驼峰:MyClass
- 方法名使用小驼峰:myMethod
- 常量全大写:MAX_VALUE
- 包名全小写:com.example.project
- 缩进用4个空格,不要用Tab
- 每行不超过80字符
- 花括号换行风格:
java复制if (condition) {
// code
} else {
// code
}
7. 明日学习路线
-
面向对象三大特性:
- 封装:访问控制符实战
- 继承:方法重写规则
- 多态:接口与抽象类
-
常用类库:
- String的不可变性
- StringBuilder线程安全问题
- 日期API比较:Date vs Calendar vs LocalDateTime
-
集合框架:
- ArrayList扩容机制
- HashMap哈希冲突解决
- 快速失败(fail-fast)机制
今天踩过最大的坑是在switch语句中忘记写break导致的case穿透问题。建议使用IDE的代码检查功能,开启所有警告提示,能避免很多低级错误。对于数组越界问题,可以用Arrays.toString()快速打印数组内容辅助调试。