Java 语言缺乏对空安全(null-safety)的内置支持,可能导致 NullPointerException 异常。这是所有Java开发的必须经历的痛苦。并且需要花大代价进行处理:使用Optional。
1.空指针异常(NullPointException)
Java 语言缺乏对空安全(null-safety)的内置支持,可能导致 NullPointerException 异常。这是所有Java开发的必须经历的痛苦。并且需要花大代价进行处理:使用Optional。
// 使用 ofNullable() 方法创建 Optional 对象
Optional<String> name = Optional.ofNullable(getName());
// 使用 map() 方法转换 Optional 对象的值,使用 orElse() 方法获取默认值
String message = name.map(n -> "Hello, " + n).orElse("Hello, Guest!");
System.out.println(message);
2.语法冗余
- 必须分号结束语句。
- 必须明确的访问修饰符:类、方法和成员变量都需要明确指定访问修饰符(如 public、private、protected)。
public class MyClass {
private int x;
protected String y;
public MyClass() {
// ...
}
public void myMethod() {
// ...
}
}
- 重复的类型声明:在 Java 中,变量声明时需要明确指定类型,这会导致代码显得更冗长。Java 10 引入了局部变量类型推断(var 关键字),可以在某些情况下减少冗余。然而,这个特性并不适用于所有场景,例如类成员变量和方法参数。
List<String> names = new ArrayList<String>();
Map<String, Integer> map = new HashMap<String, Integer>();
- 冗长的异常处理:说真的,看到下面这样的结构想死的心都有了。
public void readFile(String filePath) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(filePath));
String line = null;
while ((line = reader.readLine()) != null) {
// do something with line
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
我们实际需要的代码只有一点点:
public void readFile(String filePath) {
BufferedReader reader = new BufferedReader(new FileReader(filePath));
String line = null;
while ((line = reader.readLine()) != null) {
// do something with line
}
}
3.缺少属性(Properties)支持
Java 没有内置的属性支持,开发者需要为类的成员变量创建 getter 和 setter 方法。
4.缺少内置的函数式编程支持(Java 8 之前)
Java 8 之前,Java 缺乏对函数式编程的内置支持。虽然 Java 8 引入了 lambda 表达式和 Stream API,但仍然不如一些其他编程语言(如 Scala、Haskell)对函数式编程的支持更为丰富。
List<String> list = Arrays.asList("apple", "banana", "orange", "pear", "watermelon");
list.stream() // 这里必须.stream()才能用,感觉非常别扭
.filter(s -> s.length() >= 5)
.forEach(System.out::println);
5.类型擦除(Type Erasure)
Java 泛型的实现是基于类型擦除的,在运行时泛型类型信息会丢失,限制了泛型代码的能力,导致无法创建泛型数组和泛型实例。
T obj = new T(); // 不支持
T[] array = new T[]; // 不支持
6.基本类型与包装类型
Java 中的基本类型(如 int、float、boolean)与对应的包装类型(如 Integer、Float、Boolean)存在差异,它们在使用时可能导致不一致的行为。自动装箱和拆箱可以在某种程度上解决这个问题,但仍然需要注意。
7.受检异常(Checked Exceptions)
Java 中有两种类型的异常:受检异常(如 IOException)和非受检异常(如 NullPointerException)。受检异常必须在方法签名中声明或者进行捕获处理,这会导致异常处理的代码显得更加繁琐。
看到下面的代码,表示一脸嫌弃。
public void add() throw Exception {
//
}
8.缺少对值类型的支持
Java 语言缺乏对值类型的支持,所有对象都是引用类型,容易导致性能问题。尽管 Java 的开发团队已经意识到这个问题,正在通过 Project Valhalla 探索解决方案,但目前 Java 语言仍然不支持值类型。
9.单继承限制
Java 语言只支持单继承,一个类只能继承一个父类。虽然可以通过接口实现某种程度的多继承,但仍然不如多继承灵活。
10.可变性与不可变性
Java 语言中的类和对象默认是可变的,这可能导致数据不一致和线程安全问题。虽然可以通过一些设计模式和实践来实现不可变性,但 Java 并没有内置支持。