Java8的新特性与案例解析


Java8的新特性

  1. Lambda表达式:一种简洁、可读性高的函数式编程风格,可以更方便地编写代码。

  2. Stream API:通过流式处理数据,可以更加高效地操作集合和数组。

  3. 时间API:提供了新的时间和日期类,可以更加方便地处理时间和日期相关的操作。

  4. 接口的默认方法和静态方法:接口中可以定义默认方法和静态方法,使得接口的使用更加方便。

  5. 方法引用:可以使用已有的方法作为Lambda表达式的实现。

  6. Optional类:可以更好地处理空值问题。

  7. Nashorn引擎:一种基于JavaScript的引擎,可以在Java中使用JavaScript。

  8. 并行流:通过并行处理流,可以更加高效地处理大量数据。

  9. 新的注解:包括重复注解、类型注解等。

  10. 其他改进:包括新的Base64编码和解码API、新的ConcurrentHashMap等。

Lambda表达式

Lambda表达式是一种匿名函数,可以在Java中用来简化代码和提高可读性。以下是一些Lambda表达式的使用示例:

  1. 使用Lambda表达式来实现一个简单的计算器:
interface Calculator {
    int calculate(int a, int b);
}

Calculator add = (a, b) -> a + b;
Calculator subtract = (a, b) -> a - b;

int result1 = add.calculate(10, 5); // 15
int result2 = subtract.calculate(10, 5); // 5
  1. 使用Lambda表达式来过滤集合中的元素:
List<String> names = Arrays.asList("John", "Mary", "Peter", "David");

List<String> filteredNames = names.stream()
        .filter(name -> name.startsWith("J"))
        .collect(Collectors.toList());

System.out.println(filteredNames); // [John]
  1. 使用Lambda表达式来处理异常:
Runnable task = () -> {
    try {
        // 执行一些可能会抛出异常的代码
    } catch (Exception e) {
        // 处理异常
    }
};

new Thread(task).start();
  1. 使用Lambda表达式来排序一个集合:
List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5);

List<Integer> sortedNumbers = numbers.stream()
        .sorted((a, b) -> a.compareTo(b))
        .collect(Collectors.toList());

System.out.println(sortedNumbers); // [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]
  1. 使用Lambda表达式来创建一个线程:
Runnable task = () -> {
    System.out.println("Hello, world!");
};

new Thread(task).start();

Stream API

Stream API 是 Java 8 中引入的一种新的编程方式,它提供了一种简单、高效、灵活的处理集合数据的方式。下面是一些 Stream API 的使用示例:

  1. 过滤
List<String> names = Arrays.asList("Tom", "Jerry", "Alice", "Bob", "Jack");
List<String> result = names.stream().filter(name -> name.startsWith("J")).collect(Collectors.toList());
System.out.println(result); // 输出 [Jerry, Jack]
  1. 映射
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> squares = nums.stream().map(num -> num * num).collect(Collectors.toList());
System.out.println(squares); // 输出 [1, 4, 9, 16, 25]
  1. 排序
List<String> names = Arrays.asList("Tom", "Jerry", "Alice", "Bob", "Jack");
List<String> result = names.stream().sorted().collect(Collectors.toList());
System.out.println(result); // 输出 [Alice, Bob, Jack, Jerry, Tom]
  1. 统计
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
long count = nums.stream().count();
int sum = nums.stream().mapToInt(Integer::intValue).sum();
OptionalInt max = nums.stream().mapToInt(Integer::intValue).max();
System.out.println("count: " + count + ", sum: " + sum + ", max: " + max.getAsInt());
// 输出 count: 5, sum: 15, max: 5
  1. 匹配
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
boolean allMatch = nums.stream().allMatch(num -> num > 0);
boolean anyMatch = nums.stream().anyMatch(num -> num > 3);
boolean noneMatch = nums.stream().noneMatch(num -> num > 5);
System.out.println("allMatch: " + allMatch + ", anyMatch: " + anyMatch + ", noneMatch: " + noneMatch);
// 输出 allMatch: true, anyMatch: true, noneMatch: true
  1. 归约
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
int sum = nums.stream().reduce(0, (acc, num) -> acc + num);
Optional<Integer> product = nums.stream().reduce((acc, num) -> acc * num);
System.out.println("sum: " + sum + ", product: " + product.orElse(0));
// 输出 sum: 15, product: 120

以上代码展示了 Stream API 的一些常见用法,通过使用 Stream API,我们可以更加简洁、高效地处理集合数据。

时间API

Java 8引入了全新的时间API,提供了更加方便和易用的时间处理方式。以下是几个示例代码,展示了Java 8时间API的新改进:

  1. LocalDate

LocalDate是一个表示日期的类,可以用于存储和操作年、月、日等信息。以下是一个示例代码,展示了如何使用LocalDate来获取当前日期:

LocalDate today = LocalDate.now();
System.out.println("Today's date: " + today);
  1. LocalTime

LocalTime是一个表示时间的类,可以用于存储和操作小时、分钟、秒等信息。以下是一个示例代码,展示了如何使用LocalTime来获取当前时间:

LocalTime now = LocalTime.now();
System.out.println("Current time: " + now);
  1. LocalDateTime

LocalDateTime是一个同时表示日期和时间的类,可以用于存储和操作年、月、日、小时、分钟、秒等信息。以下是一个示例代码,展示了如何使用LocalDateTime来获取当前日期和时间:

LocalDateTime dateTime = LocalDateTime.now();
System.out.println("Current date and time: " + dateTime);
  1. Instant

Instant是一个表示时间戳的类,可以用于存储和操作以1970年1月1日为起点的秒数。以下是一个示例代码,展示了如何使用Instant来获取当前时间戳:

Instant timestamp = Instant.now();
System.out.println("Current timestamp: " + timestamp);
  1. Duration

Duration是一个表示时间间隔的类,可以用于计算两个时间点之间的差值。以下是一个示例代码,展示了如何使用Duration来计算两个时间点的差值:

LocalDateTime dateTime1 = LocalDateTime.of(2021, 1, 1, 0, 0, 0);
LocalDateTime dateTime2 = LocalDateTime.now();
Duration duration = Duration.between(dateTime1, dateTime2);
System.out.println("Duration between " + dateTime1 + " and " + dateTime2 + ": " + duration);
  1. Period

Period是一个表示日期间隔的类,可以用于计算两个日期之间的差值。以下是一个示例代码,展示了如何使用Period来计算两个日期的差值:

LocalDate date1 = LocalDate.of(2021, 1, 1);
LocalDate date2 = LocalDate.now();
Period period = Period.between(date1, date2);
System.out.println("Period between " + date1 + " and " + date2 + ": " + period);

以上是几个Java 8时间API的示例代码,展示了新的时间处理方式和更加方便的时间计算。

接口的默认方法和静态方法

Java 8 引入了接口的默认方法和静态方法,这是为了方便在接口中添加新的功能而不破坏现有的实现类。

默认方法:

默认方法是指在接口中定义的具有默认实现的方法。默认方法使用 default 关键字修饰,可以被实现类继承或重写,也可以通过接口名直接调用。

例如:

public interface MyInterface {
    default void myMethod() {
        System.out.println("Hello, world!");
    }
}

public class MyClass implements MyInterface {
    // 可以继承默认方法
}

public class Test {
    public static void main(String[] args) {
        MyInterface myObj = new MyClass();
        myObj.myMethod(); // 输出:Hello, world!
    }
}

静态方法:

静态方法是指在接口中定义的使用 static 关键字修饰的方法。静态方法只能通过接口名直接调用,不能被实现类继承或重写。

例如:

public interface MyInterface {
    static void myStaticMethod() {
        System.out.println("This is a static method!");
    }
}

public class Test {
    public static void main(String[] args) {
        MyInterface.myStaticMethod(); // 输出:This is a static method!
    }
}

方法引用

Java 8 引入了方法引用,它是一种更简洁的 Lambda 表达式语法,用于简化 Lambda 表达式的书写。方法引用是指在 Lambda 表达式中直接引用已有方法的方式。

方法引用使用双冒号(::)语法来引用方法,它可以引用静态方法、实例方法和构造方法。

  1. 静态方法引用

静态方法引用可以直接使用类名来引用静态方法,语法格式为:类名::静态方法名。

例如,假设有一个静态方法 printMessage(),我们可以使用方法引用的方式将它传递给一个函数式接口:

public class MethodReferenceExample {

    public static void printMessage() {
        System.out.println("Hello, world!");
    }

    public static void main(String[] args) {
        Runnable runnable = MethodReferenceExample::printMessage;
        Thread thread = new Thread(runnable);
        thread.start();
    }
}
  1. 实例方法引用

实例方法引用使用对象名或类名来引用实例方法,语法格式为:对象名::实例方法名 或 类名::实例方法名。

例如,假设有一个类 Person,它有一个实例方法 getName(),我们可以使用方法引用的方式将它传递给一个函数式接口:

public class MethodReferenceExample {

    public static void main(String[] args) {
        List<Person> people = Arrays.asList(new Person("Alice"), new Person("Bob"), new Person("Charlie"));

        // 使用 Lambda 表达式
        people.forEach(person -> System.out.println(person.getName()));

        // 使用方法引用
        people.forEach(Person::getName);
    }
}

class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
  1. 构造方法引用

构造方法引用使用类名来引用构造方法,语法格式为:类名::new。

例如,假设有一个类 Person,我们可以使用方法引用的方式创建它的实例:

public class MethodReferenceExample {

    public static void main(String[] args) {
        // 使用 Lambda 表达式
        Supplier<Person> supplier1 = () -> new Person();

        // 使用方法引用
        Supplier<Person> supplier2 = Person::new;
    }
}

class Person {
    public Person() {
    }
}

Optional类

Optional类是Java 8中引入的一个新类,用于解决空指针异常问题。它是一个容器对象,可以包含一个非空值或者为空。

以下是一个使用Optional类的简单例子:

import java.util.Optional;

public class OptionalExample {

    public static void main(String[] args) {
        
        // 创建一个包含非空值的Optional对象
        Optional<String> optional1 = Optional.of("Hello World");
        
        // 创建一个为空的Optional对象
        Optional<String> optional2 = Optional.empty();
        
        // 输出Optional对象的值
        System.out.println(optional1.get()); // Hello World
        
        // 如果Optional对象为空,则抛出NoSuchElementException异常
        System.out.println(optional2.get()); // 抛出NoSuchElementException异常
        
        // 判断Optional对象是否有值
        System.out.println(optional1.isPresent()); // true
        System.out.println(optional2.isPresent()); // false
        
        // 如果Optional对象为空,则返回指定的默认值
        System.out.println(optional2.orElse("Default Value")); // Default Value
        
        // 如果Optional对象为空,则执行指定的操作
        optional2.ifPresent(value -> System.out.println("Value is present"));
    }
}

在上面的例子中,我们创建了两个Optional对象,一个包含非空值,一个为空。我们使用get()方法获取包含在Optional对象中的值,但是如果Optional对象为空,则会抛出NoSuchElementException异常。因此,我们可以使用isPresent()方法判断Optional对象是否为空,或者使用orElse()方法返回一个默认值。如果我们想要在Optional对象不为空的情况下执行某些操作,可以使用ifPresent()方法。

Nashorn引擎

Nashorn是Java 8中引入的一种新的JavaScript引擎,它是基于Java虚拟机实现的,可以将JavaScript代码直接编译成Java字节码运行。下面是一个简单的Nashorn引擎示例:

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class NashornExample {
    public static void main(String[] args) throws ScriptException {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("nashorn");

        String script = "var message = 'Hello, World!';" +
                        "print(message);";

        engine.eval(script);
    }
}

这个示例代码中,我们使用了Java 8中提供的javax.script包,创建了一个ScriptEngineManager对象来获取Nashorn引擎实例。然后,我们将一个简单的JavaScript代码作为字符串传递给引擎的eval()方法,该方法会将JavaScript代码编译成Java字节码并执行。

在这个示例中,我们定义了一个JavaScript变量message,并将其赋值为字符串“Hello, World!”,然后通过print()函数将其输出到控制台。当我们运行这个Java程序时,它会输出以下内容:

Hello, World!

这表明Nashorn引擎成功地执行了我们的JavaScript代码。除了简单的输出语句,Nashorn还支持更复杂的JavaScript功能,例如函数定义、对象和数组操作等。

并行流

假设我们有一个列表,其中包含 100 个元素。我们想要对这些元素进行操作,以获得一个新的列表。在使用传统的串行流时,我们可以这样做:

List<Integer> myList = new ArrayList<>();
for (int i = 0; i < 100; i++) {
    myList.add(i);
}

List<Integer> newList = myList.stream()
    .map(num -> num * 2)
    .collect(Collectors.toList());

这将返回一个包含 100 个元素的新列表,其中每个元素都是原始列表中对应元素的两倍。但是,如果我们想要更快地执行此操作,我们可以使用 Java 8 中的并行流。这可以通过在流上调用 parallel() 方法来实现:

List<Integer> myList = new ArrayList<>();
for (int i = 0; i < 100; i++) {
    myList.add(i);
}

List<Integer> newList = myList.parallelStream()
    .map(num -> num * 2)
    .collect(Collectors.toList());

在这个例子中,我们使用了 parallelStream() 方法来将列表转换为一个并行流。这样,当我们调用 map() 方法时,每个元素都会在不同的线程上进行操作,从而加快了处理速度。最后,我们使用 collect() 方法将结果收集到一个新的列表中。

需要注意的是,并行流并不总是比串行流更快,因为它需要更多的系统资源来管理线程。因此,在使用并行流时,应该进行基准测试,以确保它确实能够提高程序的性能。

新的注解

  1. @FunctionalInterface:用于标记一个接口是函数式接口,即只包含一个抽象方法的接口。

  2. @Repeatable:用于标记一个注解可以重复使用,即可以在同一个元素上使用多次。

  3. @SafeVarargs:用于标记一个方法使用了可变参数,并且不会对参数数组中的元素进行修改操作。

  4. @SuppressWarnings:用于抑制编译器对某些代码的警告信息。

  5. @Deprecated:用于标记一个方法或类已经过时,不建议使用。

  6. @Override:用于标记一个方法是覆盖父类的方法。

  7. @Documented:用于标记一个注解可以被包含在 JavaDoc 文档中。

  8. @Retention:用于指定注解的生命周期,包括 SOURCE、CLASS 和 RUNTIME 三种生命周期。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员-小李

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值