1.lambda表达式
Lambda 表达式是 Java 8 引入的一个重要特性,它提供了一种简洁、灵活的方式来编写函数式接口的实现代码。Lambda 表达式可以用来替代匿名内部类,使得代码更加简洁易读。
Lambda 表达式的基本语法如下:
(parameter list) -> {lambda body}
参数列表:Lambda 表达式可以有零个或多个参数,多个参数使用逗号分隔。参数的类型可以明确指定,也可以根据上下文自动推断。
箭头符号:箭头符号 -> 将参数列表和 Lambda 表达式的主体分隔开。
Lambda 主体:Lambda 表达式的主体可以是一个表达式,或者是一段代码块(使用大括号括起来)。如果主体是一个表达式,则可以自动推断返回值类型;如果主体是一个代码块,则需要使用 return 语句显式返回结果。
Lambda 表达式可以用在函数式接口的实现上,函数式接口是只有一个抽象方法的接口。Lambda 表达式简化了函数式接口的实现,可以在需要函数式接口的地方直接传递 Lambda 表达式作为参数。
下面是一些 Lambda 表达式的示例:
无参数的 Lambda 表达式:
java
Runnable runnable = () -> {
System.out.println("Hello, Lambda!");
};
单个参数的 Lambda 表达式:
java
Consumer<String> consumer = (String message) -> {
System.out.println("Message: " + message);
};
多个参数的 Lambda 表达式:
java
BiFunction<Integer, Integer, Integer> add = (Integer a, Integer b) -> {
return a + b;
};
省略参数类型的 Lambda 表达式:
java
BiFunction<Integer, Integer, Integer> add = (a, b) -> {
return a + b;
};
省略大括号和返回语句的 Lambda 表达式:
java
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
Lambda 表达式的使用可以大幅简化代码,使得代码更加简洁易读。但需要注意的是,Lambda 表达式只能用于函数式接口的实现,且函数式接口只能有一个抽象方法,否则会在编译时报错。
2.函数式接口
函数式接口是指只有一个抽象方法的接口。在 Java 中,可以使用 @FunctionalInterface 注解来标识一个接口是函数式接口,以确保该接口只有一个抽象方法。
函数式接口的类型可以用于 Lambda 表达式、方法引用和构造方法引用等场景,使得代码更加简洁和灵活。
下面是一些常见的函数式接口类型及其使用示例:
Runnable:表示一个没有参数和返回值的操作。
java
Runnable runnable = () -> {
System.out.println("Hello, Lambda!");
};
Consumer<T>:表示接受一个参数并且没有返回值的操作。
java
Consumer<String> consumer = (String message) -> {
System.out.println("Message: " + message);
};
Supplier<T>:表示一个不接受参数但返回一个结果的操作。
java
Supplier<Integer> supplier = () -> {
return 42;
};
Function<T, R>:表示接受一个参数并返回一个结果的操作。
java
Function<Integer, String> function = (Integer number) -> {
return "The number is: " + number;
};
Predicate<T>:表示接受一个参数并返回一个布尔值的操作。
java
Predicate<Integer> predicate = (Integer number) -> {
return number > 0;
};
函数式接口类型可以在需要的地方使用,例如作为方法的参数或返回值类型,或者在 Lambda 表达式中进行实现。
java
public void doSomething(Runnable runnable) {
runnable.run();
}
public String process(Function<Integer, String> function, int number) {
return function.apply(number);
}
public boolean check(Predicate<Integer> predicate, int number) {
return predicate.test(number);
}
// 使用示例
doSomething(() -> System.out.println("Hello, Lambda!"));
String result = process((Integer number) -> {
return "The number is: " + number;
}, 42);
boolean isPositive = check((Integer number) -> {
return number > 0;
}, -5);
3.stream流的方法具体使用
Stream 是 Java 8 引入的一个用于处理集合数据的 API,它提供了一种流式操作的方式,可以方便地对集合进行过滤、映射、排序、分组等操作。
Stream 的方法可以分为两类:中间操作和终端操作。
中间操作: 中间操作是指对流进行转换、过滤、映射等操作,可以链式调用多个中间操作。中间操作不会立即执行,只有在遇到终端操作时才会执行。
常用的中间操作方法包括:
filter(Predicate<T> predicate):根据指定的条件过滤流中的元素。
map(Function<T, R> mapper):将流中的元素进行映射转换。
sorted(Comparator<T> comparator):对流中的元素进行排序。
distinct():去除流中的重复元素。
limit(long maxSize):截取流中的前 N 个元素。
skip(long n):跳过流中的前 N 个元素。
示例:
java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> filtered = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
// 结果:[2, 4]
终端操作: 终端操作是指对流进行最终的操作,如收集结果、遍历元素等。终端操作会触发流的执行,并产生最终的结果。
常用的终端操作方法包括:
collect(Collector<T, A, R> collector):将流中的元素收集到一个集合中。
forEach(Consumer<T> action):对流中的每个元素执行指定的操作。
count():返回流中元素的个数。
anyMatch(Predicate<T> predicate):判断流中是否存在满足指定条件的元素。
allMatch(Predicate<T> predicate):判断流中是否所有元素都满足指定条件。
noneMatch(Predicate<T> predicate):判断流中是否没有满足指定条件的元素。
示例:
java
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
long count = names.stream()
.filter(name -> name.length() > 4)
.count();
// 结果:2
Stream 提供了丰富的方法来处理集合数据,通过链式调用中间操作和终端操作,可以灵活地处理集合中的元素。通过使用 Stream,可以使代码更加简洁、可读性更高,并且可以充分利用多核处理器的并行能力来提高性能。
4.jdk8的时间api
在 JDK 8 中引入了新的时间和日期 API,用于替代旧的 java.util.Date 和 java.util.Calendar 类。新的时间和日期 API 提供了更加简洁、易用和线程安全的操作方式。
新的时间和日期 API 的主要类如下:
LocalDate:表示日期,不包含具体的时间和时区信息。
LocalTime:表示时间,不包含具体的日期和时区信息。
LocalDateTime:表示日期和时间,不包含时区信息。
Instant:表示时间戳,精确到纳秒级别。
Duration:表示时间间隔,可以用于计算两个时间点之间的差值。
Period:表示日期间隔,可以用于计算两个日期之间的差值。
ZoneId:表示时区。
ZonedDateTime:表示带时区的日期和时间。
使用新的时间和日期 API,可以进行各种时间和日期的操作,如创建日期、解析日期字符串、格式化日期、比较日期、计算日期间隔等。
下面是一些常用的示例:
创建日期和时间:
java
LocalDate date = LocalDate.now(); // 当前日期
LocalTime time = LocalTime.now(); // 当前时间
LocalDateTime dateTime = LocalDateTime.now(); // 当前日期和时间
Instant instant = Instant.now(); // 当前时间戳
解析日期字符串:
java
LocalDate date = LocalDate.parse("2022-01-01");
LocalTime time = LocalTime.parse("10:30:00");
LocalDateTime dateTime = LocalDateTime.parse("2022-01-01T10:30:00");
格式化日期和时间:
java
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = dateTime.format(formatter);
比较日期和时间:
java
LocalDate date1 = LocalDate.of(2022, 1, 1);
LocalDate date2 = LocalDate.of(2022, 2, 1);
boolean isBefore = date1.isBefore(date2);
boolean isAfter = date1.isAfter(date2);
计算日期间隔:
java
LocalDate date1 = LocalDate.of(2022, 1, 1);
LocalDate date2 = LocalDate.of(2022, 2, 1);
Period period = Period.between(date1, date2);
int days = period.getDays();
转换时区:
java
ZoneId zoneId1 = ZoneId.of("Asia/Shanghai");
ZoneId zoneId2 = ZoneId.of("America/New_York");
ZonedDateTime dateTime1 = ZonedDateTime.of(dateTime, zoneId1);
ZonedDateTime dateTime2 = dateTime1.withZoneSameInstant(zoneId2);