1.Java的优势?
简答
跨平台、提供垃圾自动回收功能、生态圈丰富
扩展
- Java是跨平台的,不同平台执行的机器码是不一样的,而Java因为加了一层中间层,所以可以做到一次编写多平台运行,即Write once,Run anywhere。
- Java提供垃圾自动回收功能,在内存较充裕的当下,将内存的管理交给GC来做,减轻了程序员编程的负担,提升了开发效率。(手动管理内存意味着自由、精细化地掌控,但是很容易出错。)
- Java生态圈非常丰富,有丰富的第三方类库、网上全面的资料、企业级框架、各种中间件等。
2.JDK1.8(Java 8)的新特性
简答
- 用元空间代替了永久代
- 引入了Lambda表达式
- 引入了日期类、接口默认方法、静态方法
- 新增Stream流式接口
- 引入了Optional类
- 新增了CompletableFeture、StampedLock等并发实现类
- 修改了HashMap、ConcurrentHashMap的实现
扩展
1.Lambda表达式
Lambda 是Java 8引入的一种匿名函数,可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码,其本质是作为函数式接口的实例,示例如下:
// 传统方式
Runnable runnable1 = new Runnable() {
@Override
public void run() {
System.out.println("mianshiya.com");
}
};
// Lambda 表达式
Runnable runnable2 = () -> System.out.println("mianshiya.com");
2.日期类
Java 8引入了新的日期和时间API(位于java.time包中),它们更加简洁和易于使用,解决了旧版日期时间API的许多问题。
例如Date ,Calendar都是可变类且线程不安全。而新的日期类都是不可变的,一旦创建就不能修改,这样可以避免意外的修改,提升代码的安全性和可维护性。
interface MyInterface {
default void defaultMethod() {
System.out.println("Default Method");
}
static void hello() {
System.out.println("Hello, New Static Method Here");
}
}
Date本身不包含时区信息,必须使用Calendar类来处理时区,但使用起来非常复杂且容易出错。
新API提供了专门的时区类(如ZonedateTime ,OffsetDateTime,ZoneId等),简化了时区处理,并且这些类的方法更加直观和易用。
3.接口默认方法、静态方法
默认方法允许在接口中定义方法的默认实现,这样接口的实现类不需要再实现这些方法。之所以提供静态方法,是为了将相关的方法内聚在接口中,而不必创建新的对象。示例如下:
interface MyInterface {
default void defaultMethod() {
System.out.println("Default Method");
}
static void hello() {
System.out.println("Hello, New Static Method Here");
}
}
4.Stream流式接口
Stream API提供了一种高效且易于使用的方式来处理数据集合。它支持链式操作、惰性求值和并行处理。示例如下:
List<String> list = Arrays.asList("a", "b", "c", "d");
List<String> result = list.stream()
.filter(s -> s.startsWith("a"))
.collect(Collectors.toList());
5.Optional类
Optional类是Java 8引入的一个容器类,它用来表示一个值可能存在或不存在。
Optional可以给返回结果提供了一个表示无结果的值,而不是返回null(网上比较流行的说法是Optional可以避免空指针,其实不是很准确)。常用方式如下:
Optional<User> userOption = Optional.ofNullable(userService.getUser(...));
if (!userOption.isPresent()) {....}
Optional类用来解决可能出现的NullPointerException问题,提供了一种优雅的方式来处理可能为空的值。
使用Optional的好处
可以简化平日里一系列判断null的操作,使得用起来的时候看着不需要判断null,不需要担心出现空指针的情况(该有的判断Optional替我们完成了)。
如下是使用与不使用Optional类的代码对比:
//没有使用Optional
Yes yes = getYes();
if (yes != null) {
Address yesAddress = yes.getAddress();
if (yesAddress != null) {
Province province = yesAddress.getProvince();
System.out.println(province.getName());
}
}
throw new NoSuchElementException(); //如果没找到就抛错
//使用Optional
Optional.ofNullable(getYes())
.map(a -> a.getAddress())
.map(p -> p.getProvince())
.map(n -> n.getName())
.orElseThrow(NoSuchElementException::new);
如果用了Optional,代码里不需要判空的操作,即使address、province为空的话,也不会产生空指针错误。
6.CompletableFuture
CompletableFuture提供了一个新的异步编程模型,简化了异步任务的编写和管理。
CompletableFuture.supplyAsync(() -> "Hello")
.thenApply(s -> s + " World")
.thenAccept(System.out::println);
7.StampedLock
StampedLock可以认为是读写锁的“改进“版本。
读写锁读写是互斥的,而StampedLock搞了个悲观读和乐观读,悲观读和写是互斥的,乐观读则不会。官方示例代码如下:
class Point {
private double x, y;
private final StampedLock sl = new StampedLock();
void move(double deltaX, double deltaY) { // an exclusively locked method
long stamp = sl.writeLock(); //获取写锁
try {
x += deltaX;
y += deltaY;
} finally {
sl.unlockWrite(stamp); //释放写锁
}
}
double distanceFromOrigin() { // A read-only method
long stamp = sl.tryOptimisticRead(); //乐观读
double currentX = x, currentY = y;
if (!sl.validate(stamp)) { //判断共享变量是否已经被其他线程写过
stamp = sl.readLock(); //如果被写过则升级为悲观读锁
try {
currentX = x;
currentY = y;
} finally {
sl.unlockRead(stamp); //释放悲观读锁
}
}
return Math.sqrt(currentX * currentX + currentY * currentY);
}
void moveIfAtOrigin(double newX, double newY) { // upgrade
// Could instead start with optimistic, not read mode
long stamp = sl.readLock(); //获取读锁
try {
while (x == 0.0 && y == 0.0) {
long ws = sl.tryConvertToWriteLock(stamp); //升级为写锁
if (ws != 0L) {
stamp = ws;
x = newX;
y = newY;
break;
}
else {
sl.unlockRead(stamp);
stamp = sl.writeLock();
}
}
} finally {
sl.unlock(stamp);
}
}
}
乐观锁就是获取判断—下,如果被修改了那么就升级为悲观锁。
但是StampedLock是不可重入锁,而且也不支持condition。并且如果线程使用writeLock()或者readLock()获得锁之后,线程还没执行完就被interrupt()的话,会导致CPU飙升,需要用
readLockInterruptibly或者writeLockInterruptibly 。