Java Development Kit (JDK) 1.8是Java渠道的一个版本,它引进了许多新的高级特性。以下是JDK 1.8及之后的一些高级特性:
- Lambda表达式:Lambda表达式是一种匿名函数,它能够传递给办法作为参数,并且能够简化代码。运用Lambda表达式能够写出愈加简练、易于了解的代码。
- Stream API:Stream API是一种新的API,它能够让开发人员愈加方便地处理调集数据。运用Stream API能够完成愈加简练、易于了解的代码。
- 函数式接口:函数式接口是一种只要一个抽象办法的接口,它能够用于Lambda表达式和办法引证。Java 8供给了许多预界说的函数式接口,例如Function、Predicate和Supplier。
- 默许办法:默许办法是一种在接口中界说的具有默许完成的办法。默许办法能够使接口愈加灵敏,因为它们能够在不损坏现有完成的情况下添加新的办法。
- 重复注解:重复注解是一种在同一个元素上多次运用相同注解的办法。Java 8答应在同一个元素上运用多个相同的注解,这使得代码愈加简练。
- 类型注解:类型注解是一种在代码中运用注解来阐明类型的办法。Java 8答应在类型上运用注解,这使得代码愈加明晰和易于了解。
- 新的日期和时刻API:Java 8引进了新的日期和时刻API,它供给了愈加简略、易于运用的日期和时刻处理办法。
- Optional类:Optional类是一种新的类,它能够用来表明一个可能为空的值。这样一来,开发者就能够愈加方便地处理可能为空的值了。
Stream API 代码示例
- 流的创立
创立流最常用的办法是将一个调集转化成流。例如,能够经过以下代码将一个List转化为流:
iniCopy code
List<String> list = Arrays.asList("apple", "banana", "orange");
Stream<String> stream = list.stream();
除此之外,还能够运用Stream.of()办法创立流:
arduinoCopy code
Stream<String> stream = Stream.of("apple", "banana", "orange");
- 中间操作
中间操作是指在流上履行的操作,这些操作回来一个新的流,能够链式调用。以下是一些常用的中间操作:
- filter():依据指定条件过滤元素。
- map():对每个元素履行指定操作,并回来一个新的流。
- flatMap():将一个流中的每个元素转化为另一个流,并将一切流合并成一个新的流。
- distinct():去重,回来一个包括不同元素的新流。
- sorted():依据指定条件对元素进行排序。
例如,能够运用filter()和map()办法来从一个字符串列表中获取长度大于5的字符串,并将它们转化为大写字母:
iniCopy code
List<String> list = Arrays.asList("apple", "banana", "orange", "watermelon");
Stream<String> stream = list.stream()
.filter(s -> s.length() > 5)
.map(String::toUpperCase);
- 终端操作
终端操作是指在流上履行的终究操作,这些操作会回来一个成果或者履行一个副作用。以下是一些常用的终端操作:
- forEach():对每个元素履行指定操作。
- collect():将流中的元素收集到一个调集中。
- reduce():运用指定操作将流中的元素合并成一个成果。
- count():回来流中元素的数量。
- anyMatch()、allMatch()、noneMatch():判别流中是否存在满意指定条件的元素。
下面是一些Stream API的高级用法及代码示例:
- Map和FlatMap操作
Map操作能够将一个流中的元素依照指定的规矩进行转化,例如将一个字符串流中的每个字符串转化为大写形式。
javaCopy code
List<String> list = Arrays.asList("apple", "banana", "orange");
List<String> upperList = list.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(upperList); // [APPLE, BANANA, ORANGE]
FlatMap操作能够将多个流合并成一个流,例如将多个字符串流合并成一个字符串流。
javaCopy code
List<List<String>> lists = Arrays.asList(
Arrays.asList("apple", "banana"),
Arrays.asList("orange", "peach"),
Arrays.asList("watermelon", "grape")
);
List<String> flatList = lists.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
System.out.println(flatList); // [apple, banana, orange, peach, watermelon, grape]
- Filter操作
Filter操作能够依据指定的条件过滤流中的元素,例如过滤出一个整数流中的一切偶数。
javaCopy code
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> evenList = list.stream()
.filter(x -> x % 2 == 0)
.collect(Collectors.toList());
System.out.println(evenList); // [2, 4, 6]
- Reduce操作
Reduce操作能够将流中的元素依照指定的规矩进行核算,例如求一个整数流中的一切元素的和。
javaCopy code
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
int sum = list.stream()
.reduce(0, Integer::sum);
System.out.println(sum); // 21
- Collect操作
Collect操作能够将流中的元素收集到一个调集中,例如将一个字符串流中的元素收集到一个List中。
javaCopy code
List<String> list = Arrays.asList("apple", "banana", "orange");
List<String> newList = list.stream()
.collect(Collectors.toList());
System.out.println(newList); // [apple, banana, orange]
- GroupingBy操作
GroupingBy操作能够将流中的元素依照指定的规矩进行分组,例如将一个字符串流中的元素依照首字母进行分组。
javaCopy code
List<String> list = Arrays.asList("apple", "banana", "orange", "avocado");
Map<Character, List<String>> map = list.stream()
.collect(Collectors.groupingBy(s -> s.charAt(0)));
System.out.println(map); // {a=[apple, avocado], b=[banana], o=[orange]}
- Sorted操作
Sorted操作能够对流中的元素进行排序,例如依照字符串长度对一个字符串流进行排序。
javaCopy code
List<String> list = Arrays.asList("apple", "banana", "orange", "avocado");
List<String> sortedList = list.stream()
.sorted(Comparator.comparing(String::length))
.collect(Collectors.toList());
System.out.println(sortedList); // [apple, banana, orange, avocado]
- Peek操作
Peek操作能够对流中的元素进行操作,例如打印出一个整数流中的每个元素。
javaCopy code
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> newList = list.stream()
.peek(System.out::println)
.collect(Collectors.toList());
- Distinct操作
Distinct操作能够对流中的元素进行去重,例如去重一个整数流中的元素。
javaCopy code
List<Integer> list = Arrays.asList(1, 2, 3, 2, 4, 5, 4, 6);
List<Integer> distinctList = list.stream()
.distinct()
.collect(Collectors.toList());
System.out.println(distinctList); // [1, 2, 3, 4, 5, 6]
- Limit和Skip操作
Limit操作能够对流中的元素进行约束,例如约束一个整数流中的元素个数。
javaCopy code
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> newList = list.stream()
.limit(3)
.collect(Collectors.toList());
System.out.println(newList); // [1, 2, 3]
Skip操作能够对流中的元素进行越过,例如越过一个整数流中的前两个元素。
javaCopy code
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> newList = list.stream()
.skip(2)
.collect(Collectors.toList());
System.out.println(newList); // [3, 4, 5, 6]
- Parallel操作
Parallel操作能够将流中的元素进行并行处理,然后进步处理效率。例如对一个整数流中的元素进行并行处理。
javaCopy code
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
int sum = list.parallelStream()
.reduce(0, Integer::sum);
System.out.println(sum); // 21
- Max和Min操作
Max和Min操作能够求出流中的最大值和最小值,例如求一个整数流中的最大值和最小值。
javaCopy code
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
int max = list.stream()
.max(Integer::compare)
.orElse(0);
int min = list.stream()
.min(Integer::compare)
.orElse(0);
System.out.println("max: " + max + ", min: " + min); // max: 6, min: 1
- Match操作
Match操作能够判别流中的元素是否满意指定的条件,例如判别一个整数流中是否存在大于10的元素。
javaCopy code
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
boolean anyMatch = list.stream()
.anyMatch(x -> x > 10);
boolean allMatch = list.stream()
.allMatch(x -> x > 0);
boolean noneMatch = list.stream()
.noneMatch(x -> x < 0);
System.out.println("anyMatch: " + anyMatch + ", allMatch: " + allMatch + ", noneMatch: " + noneMatch);
新的日期和时刻API 代码示例
当涉及到日期和时刻操作时,Java曾经的Date和Calendar类不行灵敏,而且运用起来比较麻烦。JDK 1.8引进了一组新的日期和时刻API,供给了愈加简略易用的日期和时刻操作办法。下面是一些新的日期和时刻API的示例代码:
- LocalDate类
LocalDate类表明一个不可变的日期目标,它只包括日期信息,不包括时刻和时区信息。它的实例能够经过静态工厂办法LocalDate.of()创立。下面是一些示例代码:
javaCopy code// 创立LocalDate目标
LocalDate date = LocalDate.of(2022, 1, 1);
// 获取年、月、日信息
int year = date.getYear();
int month = date.getMonthValue();
int day = date.getDayOfMonth();
// 获取星期信息
DayOfWeek dow = date.getDayOfWeek();
int dowValue = dow.getValue(); // 1表明星期一,7表明星期日
// 比较日期
LocalDate today = LocalDate.now();
if (date.isBefore(today)) {
System.out.println("日期在今日之前");
} else if (date.isAfter(today)) {
System.out.println("日期在今日之后");
} else {
System.out.println("日期便是今日");
}
- LocalTime类
LocalTime类表明一个不可变的时刻目标,它只包括时刻信息,不包括日期和时区信息。它的实例能够经过静态工厂办法LocalTime.of()创立。下面是一些示例代码:
javaCopy code// 创立LocalTime目标
LocalTime time = LocalTime.of(12, 30, 0);
// 获取小时、分钟、秒信息
int hour = time.getHour();
int minute = time.getMinute();
int second = time.getSecond();
// 比较时刻
LocalTime now = LocalTime.now();
if (time.isBefore(now)) {
System.out.println("时刻在现在之前");
} else if (time.isAfter(now)) {
System.out.println("时刻在现在之后");
} else {
System.out.println("时刻便是现在");
}
- LocalDateTime类
LocalDateTime类表明一个不可变的日期时刻目标,它包括日期和时刻信息,但不包括时区信息。它的实例能够经过静态工厂办法LocalDateTime.of()创立。下面是一些示例代码:
javaCopy code// 创立LocalDateTime目标
LocalDateTime dateTime = LocalDateTime.of(2022, 1, 1, 12, 30, 0);
// 获取年、月、日、小时、分钟、秒信息
int year = dateTime.getYear();
int month = dateTime.getMonthValue();
int day = dateTime.getDayOfMonth();
int hour = dateTime.getHour();
int minute = dateTime.getMinute();
int second = dateTime.getSecond();
// 比较日期时刻
LocalDateTime now = LocalDateTime.now();
if (dateTime.isBefore(now)) {
System.out.println("日期时刻在现在之前");
} else if (dateTime.isAfter(now)) {
System.out.println("日期时刻在现在之后");
} else {
System.out.println("日期时刻便是现在");
}
- ZonedDateTime类
ZonedDateTime类表明一个带时区的日期时刻目标,它包括日期、时刻和时区信息。它的实例能够经过静态工厂办法ZonedDateTime.of()创立。下面是一些示例代码:
javaCopy code// 创立ZonedDateTime目标
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
ZonedDateTime zonedDateTime = ZonedDateTime.of(2022, 1, 1, 12, 30, 0, 0, zoneId);
// 获取年、月、日、小时、分钟、秒、时区信息
int year = zonedDateTime.getYear();
int month = zonedDateTime.getMonthValue();
int day = zonedDateTime.getDayOfMonth();
int hour = zonedDateTime.getHour();
int minute = zonedDateTime.getMinute();
int second = zonedDateTime.getSecond();
ZoneId zone = zonedDateTime.getZone();
// 转化时区
ZonedDateTime newYorkTime = zonedDateTime.withZoneSameInstant(ZoneId.of("America/New_York"));
// 比较日期时刻
ZonedDateTime now = ZonedDateTime.now();
if (zonedDateTime.isBefore(now)) {
System.out.println("日期时刻在现在之前");
} else if (zonedDateTime.isAfter(now)) {
System.out.println("日期时刻在现在之后");
} else {
System.out.println("日期时刻便是现在");
}
- DateTimeFormatter类
DateTimeFormatter类用于格局化和解析日期时刻字符串。它的实例能够经过静态工厂办法DateTimeFormatter.ofPattern()创立。下面是一些示例代码:
用于将日期时刻格局化为指定的字符串:
javaCopy code
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class DateTimeFormatterDemo {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = now.format(formatter);
System.out.println("Formatted date-time: " + formattedDateTime);
}
}
这个示例程序中,获取了当时的日期和时刻,然后创立了一个 DateTimeFormatter 目标,运用 ofPattern() 办法指定了要格局化的日期时刻字符串的格局。在最后一行代码中,将当时的日期时刻格局化为指定的字符串,并将其打印到控制台上。
其他示例:
- 解析字符串为日期时刻
javaCopy code
String strDateTime = "2022-01-01 12:30:45";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime dateTime = LocalDateTime.parse(strDateTime, formatter);
System.out.println("Parsed date-time: " + dateTime);
在这个示例中,首要创立了一个日期时刻字符串,然后运用 DateTimeFormatter 类的 parse() 办法将其解析为一个 LocalDateTime 目标,并将其打印到控制台上。
- 自界说本地化格局化器
javaCopy code
Locale locale = Locale.CHINA;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss", locale);
String formattedDateTime = LocalDateTime.now().format(formatter);
System.out.println("Formatted date-time: " + formattedDateTime);
在这个示例中,首要创立了一个 Locale 目标,用于指定本地化信息,然后创立了一个 DateTimeFormatter 目标,运用 ofPattern() 办法指定了要格局化的日期时刻字符串的格局,并将 Locale 目标传递给它。在最后一行代码中,将当时的日期时刻格局化为指定的字符串,并将其打印到控制台上。
- 运用预界说的格局化器
javaCopy code
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
String formattedDateTime = formatter.format(now);
System.out.println("Formatted date-time: " + formattedDateTime);
在这个示例中,运用了 DateTimeFormatter 类供给的一个预界说的格局化器 ISO_LOCAL_DATE_TIME,它能够将日期时刻格局化为 ISO 8601 格局。将当时的日期时刻格局化为指定的字符串,并将其打印到控制台上。
函数式接口 代码示例
下面是一些常用的函数式接口及其代码示例:
- Consumer 接口:承受一个参数并回来 void,用于履行一些操作。
javaCopy code
Consumer<String> print = str -> System.out.println(str);
System.out.println("Hello world!"); // 输出 "Hello world!"
- Supplier 接口:不承受参数,回来一个值。
javaCopy code
Supplier<Integer> randomNumber = () -> (int) (Math.random() * 100);
System.out.println(randomNumber.get()); // 输出一个随机数
- Function 接口:承受一个参数并回来一个值。
javaCopy code
Function<Integer, Integer> square = x -> x * x;
System.out.println(square.apply(5)); // 输出 25
- Predicate 接口:承受一个参数并回来一个 boolean 值,用于判别条件是否建立。
javaCopy code
Predicate<Integer> isEven = x -> x % 2 == 0;
System.out.println(isEven.test(4)); // 输出 true
- BiFunction 接口:承受两个参数并回来一个值。
javaCopy code
BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
System.out.println(add.apply(2, 3)); // 输出 5
以上是一些常用的函数式接口及其代码示例。这些接口能够用于Lambda表达式、办法引证等语法中,使得Java中的函数式编程愈加方便。
假设有一个 User 类,其中包括 name 和 age 两个属性,需求依据用户的年纪对用户列表进行排序,并输出排序后的成果。运用函数式接口能够让代码愈加简练易懂。
javaCopy code
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User("张三", 20));
userList.add(new User("李四", 18));
userList.add(new User("王五", 25));
userList.add(new User("赵六", 22));
// 依据年纪排序
userList.sort(Comparator.comparingInt(User::getAge));
// 输出排序成果
userList.forEach(user -> System.out.println(user.getName() + " " + user.getAge()));
}
}
在上面的示例中,运用了 Comparator 函数式接口来界说排序规矩,并运用 forEach 办法输出排序后的成果。这样的代码愈加简练易懂,也愈加符合函数式编程的思维。
再比方:
- BiConsumer 接口:承受两个参数并回来 void,用于履行一些操作。
javaCopy code
BiConsumer<String, Integer> print = (str, num) -> System.out.println(str + num);
print.accept("The answer is ", 42); // 输出 "The answer is 42"
- UnaryOperator 接口:承受一个参数并回来一个与参数类型相同的值。
javaCopy code
UnaryOperator<Integer> square = x -> x * x;
System.out.println(square.apply(5)); // 输出 25
- BinaryOperator 接口:承受两个参数并回来一个与参数类型相同的值。
javaCopy code
BinaryOperator<Integer> add = (x, y) -> x + y;
System.out.println(add.apply(2, 3)); // 输出 5
- BiPredicate 接口:承受两个参数并回来一个 boolean 值,用于判别条件是否建立。
javaCopy code
BiPredicate<Integer, Integer> isGreaterThan = (x, y) -> x > y;
System.out.println(isGreaterThan.test(5, 3)); // 输出 true
- BiFunction 接口:承受两个参数并回来一个值。
javaCopy code
BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
System.out.println(add.apply(2, 3)); // 输出 5
这些函数式接口能够让代码愈加简练易懂,并且能够防止一些冗长的代码。在实践开发中,能够依据详细的需求选择适宜的函数式接口来运用。
Lambda 表达式 代码示例
Lambda 表达式的语法:
iniCopy code
(parameter1, parameter2, ..., parameterN) -> { statement1; statement2; ... statementN; }
Lambda 表达式由三部分组成:
- 参数列表:由逗号分隔的形式参数列表,能够为空。
- 箭头符号:由连字符和大于号组成,用于分隔参数列表和 Lambda 表达式的主体。
- Lambda 表达式主体:能够是一个表达式或一个代码块,用于履行一些操作。
Lambda 表达式能够有零个、一个或多个参数,参数类型能够显式指定,也能够依据上下文揣度出来。Lambda 表达式主体能够是一个表达式或一个代码块,假如是一个表达式,则能够省略大括号和 return 关键字。
下面是一些示例:
javaCopy code// 无参数
Runnable runnable = () -> System.out.println("Hello world!");
// 一个参数
Consumer<String> print = str -> System.out.println(str);
// 多个参数
BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
// 多条句子
Runnable runnable = () -> {
System.out.println("Hello");
System.out.println("World");
};
// 表达式主体
Function<Integer, Integer> square = x -> x * x;
Lambda 表达式是 Java 8 中引进的一个重要特性,它能够让代码愈加简练易懂,并且能够防止一些冗长的代码。
表达式的代码示例:
- 运用 Lambda 表达式完成 Runnable 接口
javaCopy code
Runnable runnable = () -> System.out.println("Hello world!");
new Thread(runnable).start(); // 输出 "Hello world!"
- 运用 Lambda 表达式完成 ActionListener 接口
javaCopy code
JButton button = new JButton("Click me!");
button.addActionListener(event -> System.out.println("Button clicked!"));
- 运用 Lambda 表达式完成 Comparator 接口
javaCopy codeList<String> list = new ArrayList<>();
list.add("apple");
list.add("banana");
list.add("orange");
// 依据字符串长度排序
list.sort((str1, str2) -> str1.length() - str2.length());
// 输出排序成果
list.forEach(str -> System.out.println(str));
- 运用 Lambda 表达式完成 Predicate 接口
javaCopy code
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
// 打印出一切偶数
list.stream().filter(num -> num % 2 == 0).forEach(num -> System.out.println(num));
- 运用 Lambda 表达式完成 Consumer 接口
javaCopy code
List<String> list = new ArrayList<>();
list.add("apple");
list.add("banana");
list.add("orange");
// 输出每个字符串的长度
list.forEach(str -> System.out.println(str.length()));
以上是一些常用的 JDK Lambda 表达式的示例。这些示例能够协助你更好地了解 Lambda 表达式的运用办法和语法。在实践开发中,能够依据详细的需求运用 Lambda 表达式来简化代码。
Optional 类 示例
Optional 类的代码示例:
- 创立 Optional 目标
javaCopy code
Optional<String> optional = Optional.of("Hello world!");
- 判别 Optional 目标是否为空
javaCopy code
Optional<String> optional = Optional.ofNullable(null);
if (optional.isPresent()) {
System.out.println(optional.get());
} else {
System.out.println("Optional is empty");
}
- 获取 Optional 目标的值
javaCopy code
Optional<String> optional = Optional.of("Hello world!");
System.out.println(optional.get());
- 假如 Optional 目标不为空,则履行一些操作
javaCopy code
Optional<String> optional = Optional.of("Hello world!");
optional.ifPresent(str -> System.out.println(str));
- 假如 Optional 目标不为空,则回来它的值,不然回来一个默许值
javaCopy code
Optional<String> optional = Optional.ofNullable(null);
String str = optional.orElse("Default value");
System.out.println(str);
- 假如 Optional 目标不为空,则回来它的值,不然回来一个由 Supplier 接口供给的默许值
javaCopy code
Optional<String> optional = Optional.ofNullable(null);
String str = optional.orElseGet(() -> "Default value");
System.out.println(str);
- 假如 Optional 目标不为空,则回来它的值,不然抛出一个由 Supplier 接口供给的反常
javaCopy code
Optional<String> optional = Optional.ofNullable(null);
String str = optional.orElseThrow(() -> new RuntimeException("Value is null"));
以上是一些常用的 JDK Optional 类的示例。这些示例能够协助你更好地了解 Optional 类的运用办法和语法。在实践开发中,能够依据详细的需求运用 Optional 类来处理可能为空的值,防止空指针反常的呈现。
结语
JDK 1.8 的新特性和改善能够协助开发人员更高效地编写 Java 应用程序,然后进步生产力和产能。下期再会!