java新应用_java8新特性的实际应用
Java8自从14年发布之后增加了很多新特性,其中好多特性在实际应用中都可以用到,不仅简化了我们代码,还弥补了旧版本里的一些不足。这里只列举出一些实际开发中可能用得到的特性,加以说明。
函数式接口
函数式接口就是有且仅有一个抽象函数的接口,在java8之前就有一些函数是接口,比如java.util.Comparator,以前我们用到这种接口的时候,一般使用匿名内部类来进行实现,如下,我们定义一个Person类:
@Data
@AllArgsConstructor
@NoArgsConstructor
class Person {
private Integer id;
private String name;
private Integer age;
public static List getList() {
return Arrays.asList(
new Person(1, "1号", 19),
new Person(2, "2号", 16),
new Person(3, "3号", 20),
new Person(4, "4号", 19),
new Person(5, "5号", 14));
}
}
例如我们要实现按照年龄排序,就要实现一个Comparator类,重写compare方法:
public static void main(String[] args) {
List list = Person.getList();
list.sort(new Comparator() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge();
}
});
list.forEach(System.out::println);
}
运行结果如下:
在java8之后就可以使用Lambda表达式来表示该接口的一个实现,如下:
public static void main(String[] args) {
List list = Person.getList();
list.sort((o1, o2) -> o1.getAge() - o2.getAge());
list.forEach(System.out::println);
}
方法引用
方法引用通过方法的名字来指向一个方法,可以使语言的构造更紧凑简洁,减少冗余代码。
例如上面代码中的list.forEach(System.out::println);就引用了println方法,继续优化上面的代码,我们可以使用方法引用来对集合进行排序:
public static void main(String[] args) {
List list = Person.getList();
list.sort(Comparator.comparingInt(Person::getAge));
list.forEach(System.out::println);
}
stream
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
我们可以通过以下两种方式生成流对象:
stream() − 为集合创建串行流。
parallelStream() − 为集合创建并行流。
下面介绍几个常用的方法:
filter
filter接受一个返回值为布尔类型的函数作为参数,该函数可以用Lambda表达式表示。顾名思义,filter可用于过滤出集合中满足条件元素。
例如我们要在刚才定义的集合中找到年龄为19岁的:
public static void main(String[] args) {
List list = Person.getList();
list.stream().filter(person -> person.getAge() == 19).forEach(System.out::println);
}
运行结果:
map
map就是将对应的元素按照给定的方法进行转换,参数为Lambda表达式形式或者是方法引用。
例如我们要获得所有person对象的name:
public static void main(String[] args) {
List list = Person.getList();
list.stream().map(person -> person.getName()).forEach(System.out::println);
}
或者使用函数引用:
public class Test02 {
public static void main(String[] args) {
List list = Person.getList();
list.stream().map(Person::getName).forEach(System.out::println);
}
}
运行结果:
flatMap
和map像似,都是将对应元素按照对应的方法进行转换,但是区别在于map只能一对一,而flatMap可以一对多转换。
例如我们要获取文章集合中的所有标签,多个标签用逗号隔开。
文章类的定义如下:
@Data
@AllArgsConstructor
@NoArgsConstructor
class Article {
private String title;
private Integer id;
private String tags;
public static List getList() {
return Arrays.asList(
new Article("如何学习SpringBoot?", 1, "java,Spring"),
new Article("python学习方法总结", 2, "python,学习经验"),
new Article("sql优化", 3, "sql,数据库"),
new Article("jvm面试必考要点?", 4, "java,jvm,面试")
);
}
}
使用flatMap实现:
public static void main(String[] args) {
List list = Article.getList();
list.stream().flatMap(article -> Arrays.stream(article.getTags().split(","))).forEach(System.out::println);
}
运行结果:
但是假如使用map:
public static void main(String[] args) {
List list = Article.getList();
list.stream().map(article -> Arrays.stream(article.getTags().split(","))).forEach(System.out::println);
}
运行结果为:
可见map是能实现一对一,上面的代码只是将集合中的各个元素转换为stream类。
distinct
顾名思义,distinct可以实现去重。
例如,还是上面的标签问题,刚才打印出来的结果中存在标签重复,我们可以对其进行去重操作:
public static void main(String[] args) {
List list = Article.getList();
list.stream()
.flatMap(article -> Arrays.stream(article.getTags().split(",")))
.distinct()
.forEach(System.out::println);
}
运行结果:
sorted
使用soured可以对流中元素进行排序。
例如对person进行按照年龄排序:
public static void main(String[] args) {
List list = Person.getList();
list.stream().sorted(Comparator.comparingInt(Person::getAge)).forEach(System.out::println);
}
运行结果:
limit
限制返回的个数,例如我们只要前三个person的信息:
public static void main(String[] args) {
List list = Person.getList();
list.stream().limit(3).forEach(System.out::println);
}
运行结果:
skip
与limit相反,skip的作用是跳过前面指定个数元素,例如只显示后三个person的信息:
public static void main(String[] args) {
List list = Person.getList();
list.stream().skip(list.size() - 3).forEach(System.out::println);
}
运行结果:
min/max
求最大值或者最小值:
public static void main(String[] args) {
List list = Person.getList();
list.stream().min(Comparator.comparingInt(Person::getAge)).ifPresent(System.out::println);
}
这里的ifPresent是Optional类里面的方法,下面会谈到。
运行结果:
anyMatch/allMatch/noneMatch
返回一个boolean类型的值,其中
anyMatch:Stream 中任意一个元素符合传入的 predicate,返回 true
allMatch:Stream 中全部元素符合传入的 predicate,返回 true
noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true
public static void main(String[] args) {
List list = Person.getList();
if (list.stream().noneMatch(person -> person.getAge() > 20)) {
System.out.println("没有人年龄大于20岁");
}
if (list.stream().anyMatch(person -> person.getAge() > 15)) {
System.out.println("存在年龄大于15岁的人");
}
if (list.stream().allMatch(person -> person.getAge() > 10)) {
System.out.println("所有人年龄都大于10岁");
}
}
collect
collect在流中生成列表,map,等常用的数据结构
Optional
Optional类的出现是为了解决返回值为null的问题,以Spring Data Jpa为例,函数findById()的返回值就为一个Optional类的对象。
isPresent/get
isPresent()可以用来判断Optional对象里面的值是否为null,get()可以获取里面的值:
但是这样似乎并没有比原始的方法if(xxx==null){}好用,其实Optional主要与Lambda表达式结合才能发挥出作用。
存在就执行操作:
Person p = new Person();
Optional p1 = Optional.ofNullable(p);
p1.ifPresent(person -> {
System.out.println(person);
});
存在就返回,否则返回其他内容(例如一个返回数组的函数,如果没有数据的话一般返回一个长度为0的数组,而不是null)
private static int[] test() {
int[] ints = {1, 2, 3, 4};
Optional optional = Optional.ofNullable(ints);
return optional.orElse(new int[0]);
}
也可以由函数产生:
private static int[] test() {
int[] ints = {1, 2, 3, 4};
Optional optional = Optional.ofNullable(ints);
return optional.orElseGet(() -> {
// 一系列操作
return new int[0];
});
}
存在就返回,否则就抛出异常
private static int[] test() {
int[] ints = {1, 2, 3, 4};
Optional optional = Optional.ofNullable(ints);
return optional.orElseThrow(() -> new RuntimeException());
}
Optional类还可以进行链式操作,下面为java7的写法:
private static String getUpperName() {
Person p = new Person();
if (p != null) {
if (p.getName() != null) {
return p.getName().toUpperCase();
} else {
return null;
}
} else {
return null;
}
}
使用java8可以大量简化操作:
private static String getUpperName() {
Person p = new Person();
return Optional.ofNullable(p)
.map(person -> person.getName())
.map(name -> name.toUpperCase())
.orElse(null);
}
Java 8 日期时间 API
在旧版的 Java 中,日期时间 API 存在诸多问题,其中有:
非线程安全 − java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。
设计很差 − Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
时区处理麻烦 − 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。
java8中引入了很多新的类,使我们更加方便的操作时间与日期
LocalDate:不包含时间的日期,比如2019-10-14。可以用来存储生日,周年纪念日,入职日期等。
LocalTime:与LocalDate想对照,它是不包含日期的时间。
LocalDateTime:包含了日期及时间,没有偏移信息(时区)。
ZonedDateTime:包含时区的完整的日期时间,偏移量是以UTC/格林威治时间为基准的。
Instant:时间戳,与System.currentTimeMillis()类似。
Duration:表示一个时间段。
Period:用来表示以年月日来衡量一个时间段。
DateTimeFormatter:日期格式化类
毫秒数转LocalDateTime
实现需求:为了方便我们经常在数据库中存入毫秒数,从数据库中读取出毫秒数之后,我们可以通过以下方法转换为LocalDateTime
Instant instant = Instant.ofEpochMilli(System.currentTimeMillis());
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
格式化LocalDateTime
实现需求:我们可以将时间转换为相应格式,返回给前端
LocalDateTime localDateTime = LocalDateTime.now();
String format = localDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
String format1 = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
参考:(DateTimeFormatter自带的时间格式)
java新应用_java8新特性的实际应用相关推荐
- java stream 有序_Java8新特性之Stream流专题四 并行流
随着对流API认识的慢慢深入,本章我们要讨论的知识点是流API里面的并行流了. 在开始讨论并行流之前,我先引发一下大家的思考,就你看到这篇文章的时间,你们是不是经常听到,Intel i7 CPU什么8 ...
- java lambda 变量_java8新特性-lambda(变量捕获)
1.匿名内部类中的变量捕获 public class App { String s1 = "全局变量"; public void testInnerClass() { String ...
- java8新特性_Java8新特性之Date API|乐字节
大家好,我是乐字节的小乐,上篇文章讲述了<Java8新特性之Optional>,接下来,小乐将接着讲述Java8新特性之Date API 2019日历 Java8之Date API Jav ...
- java 模块化_Java 9 新特性 - 模块化 - Java 技术驿站-Java 技术驿站
Java 9 最大的特性就是模块化 ( Module ) 了.本章,我们就对这个 模块化 进行一些简单的讲解,包括 Java 9 模块化的概念.如何实现.如何使用等 对于 Java 9 来说,模块化 ...
- Java 11 正式发布,新特性解读
Java 11 正式发布,新特性解读 杨晓峰 2018 年 9 月 26 日 话题:Java语言 & 开发 不知不觉 JDK 11 已经发布了,从 9 开始,JDK 进入了让人学不动的更新 ...
- java的发展(8-17新特性整理)
java java的诞生与历史: 简介:Java是一门面向对象的编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承.指针等概念,因此Java语言具有功能强大和简单易用两个特征. ...
- Java基础之Java8 新特性
hp实训8.19_Java基础之Java8新特性 // 信息展示方法 ,接口中,就可以提供一种实现. 就可以使用这种功能.default void print() {System.out.printl ...
- 不停歇的Java即将发布JDK16新特性速览及从菜鸟到架构师[图]
一.不停歇的Java即将发布JDK16新特性速览 当开发者深陷Java8版本之际,这边下一版本Java16有了最新的消息,与Java15一样,作为短期版本,Oracle仅提供6个月的支持. 根据发布计 ...
- 【JAVA拾遗】Java8新特性合辑
[JAVA拾遗]Java8新特性合辑 文章目录 [JAVA拾遗]Java8新特性合辑 0. 逼逼 [--/--]126 Lambda Expressions & Virtual Extensi ...
最新文章
- ICLR 2020被爆半数审稿人无相关领域经验,同行评审制度在垮塌?
- 在线试玩,在体感游戏中打败泰森,这位小哥破解了任天堂「拳无虚发」
- 那些年,一起学的Java 7-3
- canvas - 饼状图
- (原创)c#学习笔记06--函数02--变量的作用域01--其他结构中变量的作用域
- mysql主从复制的binlog和relay-log的区别
- python 折线图 尾部_Matplotlib 折线图plot()所有用法详解
- oracle session status killed,进程状态为KILLED的进程如何杀掉
- 搜索算法-搜索的优化
- Hadoop3集群搭建之——hive添加自定义函数UDTF (一行输入,多行输出)
- 电脑如何安装php文件夹在哪个文件夹,win7系统桌面文件在c盘哪个文件夹
- vue设置页面滚动高度_vue中获取滚动高度或指定滚动到某位置
- JavaScript DOM 编程艺术(第2版)读书笔记 (7)
- 宝塔控制面板如何添加伪静态
- linux基础期末考,Linux基础期末考试试题.pdf
- 迈信EP100伺服迈信 EP100 伺服驱动器源码学习资料
- 数电(四)—使用译码器74138和门电路实现/写逻辑函数,使用8选1数据选择器74151实现实现L=∑m格式的3/多输入逻辑函数
- android toast 显示在最上面,Android Toast在屏幕上移动
- libcef-详细步骤-将cef浏览器嵌入到Win32中作为子窗口运行
- 黑马程序员:Java学习路线图上线了