本文主要介绍了JDK1.8新特性相关知识,其中包含Lambda表达式、方法引用、Stream、新时间API,在本文中结合代码对JDK1.8新特性进行了详细的分析!
一、Lambda表达式
1.简介
- Lambda表达式(又称为闭包)是整个JAVA8发现版中最受期待的在Java语言层面上的改变.
- lambda允许把函数作为一个参数
(函数作为参数传递进方法中),或者把代码看成数据
.- lambda表达式用于
简化java中接口式的匿名内部类
,被称为函数式接口的概念.函数式接口
就是一个具有一个方法的普通接口
,像这样的接口可以被隐式转换为lambda表达式
- 作用: 简化代码
要求:一个接口或抽象类中只有一个抽象方法- 优点:
1,简化代码
2,不会生成class文件- 缺点:
1,有限制
2,对新手代码阅读增加困难
2.语法
- 格式:(参数1,参数2,…)->{方法体}
- 注意:
1,一个接口中只有一个方法,可以用Lambda进行简化
2,如果一个接口中只有一个抽象方法,该接口称为函数式接口
3.Lambda表达式与函数式接口
(1)没有参数时使用lambda表达式
代码:
public class Test01 {
public static void main(String[] args) {
IEatImpl iEatImpl = new IEatImpl();
iEatImpl.eat();
IEat iEat = new IEat() {
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("吃东西01");
}
};
iEat.eat();
/**
* Labdma写法
*/
IEat iEat02 = ()->{
System.out.println("吃东西02");
};
iEat02.eat();
}
}
interface IEat{
void eat();
}
class IEatImpl implements IEat{
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("吃东西");
}
}
(2)带有参数时使用lambda表达式
代码:
public class Test01 {
public static void main(String[] args) {
IEat iEat01 = (String foodName)->{
System.out.println("吃"+foodName);
};
iEat01.eat("大嘴巴子");
IEat iEat02 = (foodName)->{
System.out.println("吃"+foodName);
};
iEat02.eat("大嘴巴子");
//方法中只有一个参数可以忽略()不写
IEat iEat03 = foodName->{
System.out.println("吃"+foodName);
};
iEat03.eat("大嘴巴子");
IEat02 iEat04 = (foodName,name)->{
System.out.println(name+"吃"+foodName);
};
iEat04.eat("大嘴巴子","张三");
}
}
interface IEat{
void eat(String foodName);
}
interface IEat02{
void eat(String foodName,String name);
}
(3)代码块中只有一句代码时使用lambda表达式
代码:
public class Test01 {
public static void main(String[] args) {
IEat iEat02 = ()->System.out.println("吃东西");
iEat02.eat();
}
}
interface IEat{
void eat();
}
(4)代码块中有多句代码时使用lambda表达式
代码:
public class Test01 {
public static void main(String[] args) {
IEat iEat = ()->{
System.out.println("准备干饭");
System.out.println("吃东西");
System.out.println("就餐完毕");
};
iEat.eat();
}
}
interface IEat{
void eat();
}
(5)有返回值得代码块
代码:
public class Test01 {
public static void main(String[] args) {
IEat iEat = ()->{
System.out.println("吃东西");
return true;
};
iEat.eat();
//有返回值得方法体只有一句代码,忽略大括号与return关键字
IEat iEat = ()->true;
iEat.eat();
}
}
interface IEat{
boolean eat();
}
(6)参数中使用final关键字
代码:
public class Test01 {
public static void main(String[] args) {
IEat iEat = (final String foodName)->{
System.out.println("吃"+foodName);
return true;
};
iEat.eat();
}
}
interface IEat{
boolean eat(final String foodName);
}
3.相关注解
@FunctionalInterface
作用:验证接口是否为函数接口
4常见函数式接口
接口名称 类型 方法
Consumer<T> 消费型接口 void accept(T t):操作t
Supplier<T> 供给型接口 T get():返回t
Function<T,R> 函数型接口 R apply(T t):操作t,返回r
Predicate<T> 断言型接口 boolean test(T t):操作t,返回boolean
二、方法引用
1.简介
- 方法引用是Lambda表达式的一种简写形式
- 要求:
如果Lambda表达式方法体中只是调用一个特点的已经存在的方法,则可以使用方法引用
2.语法
(1)对象::实例方法
要求:lambda传入的参数与就是所调用的方法的参数,并且方法体中只有一行代码
代码:
Consumer<String> consumer=s->System.out.println(s);
consumer.accept("hello");
Consumer<String> consumer2=System.out::println;
consumer2.accept("world");
(2)类::静态方法
要求:lambda传入的参数与就是所调用的方法的参数,并且方法体中只有一行代码
代码:
Comparator<Integer> com=(o1,o2)->Integer.compare(o1, o2);
Comparator<Integer> com2=Integer::compare;
(3)类::实例方法
要求:lambda传入的参数类型就是调用该方法的对象,并且方法体中只有一行代码
代码:
Function<Employee, String> function=e->e.getName();
Function<Employee, String> function2=Employee::getName;
System.out.println(function2.apply(new Employee("小明", 50000)));
class Employee{
private String name;
private int money;
public Employee(String name,int money) {
this.money = money;
this.name = name;
}
public String getName() {
return name;
}
}
(4)类::new
要求:lambda方法体中只有一行创建对象的代码,并且返回值就是该对象
代码:
Supplier<Employee> supplier=()->new Employee();
Supplier<Employee> supplier2=Employee::new;
Employee employee=supplier.get();
class Employee{
private String name;
private int money;
public Employee(String name,int money) {
this.money = money;
this.name = name;
}
public String getName() {
return name;
}
}
三、Stream
1.简介
- Stream:流
与集合类似,但是集合中存储的是数据,而Stream中存储的是对数据的操作过程- 如图:
原料 -> 工序1 -> 工序2 -> 工序n -> 产品- 注意:
1,Stream不会存储数据
2,Stream不会改变原数据,他们会返回一个持有加工后数据的新Stream
3,Stream会延迟执行,会等到需要的结果才执行
2.使用步骤
- 创建:
新建一个Stream- 中间操作:
在一个或多个步骤中,将初始Stream转换为另一个Stream的中间操作- 终止操作:
使用一个终止操作
来产生一个结果,该操作会强制之前的延迟操作立即执行.此后该Stream不能在使用
3.获取Stream
1,通过集合对象(Collection)的stream()或parallelStream()方法
代码:
ArrayList<String> arrayList=new ArrayList<>();
//并行流
Stream<String> stream = arrayList.parallelStream();
或
ArrayList<String> list = new ArrayList<String>();
Stream<String> stream = list.stream();
2,通过Arrays工具类的静态stream方法
代码:
String[] arr= {"aaa","bbb","ccc"};
Stream<String> stream2=Arrays.stream(arr);
3,通过Stream接口中的静态of,iterate,generate方法
代码:of普通流
Stream<Integer> stream = Stream.of(10,20,30,40,50);
代码:iterate迭代流
Stream<Integer> iterate = Stream.iterate(0, x->x+2);
代码:generate生成流
Stream<Integer> generate = Stream.generate(()->new Random().nextInt(100));
4,通过IntStream,LongStream,DoubleStream接口的of,range,rangeClosed方法
代码:
IntStream stream = IntStream.of(100,200,300);
代码:
IntStream range = IntStream.rangeClosed(0, 50);
4.中间操作
1,filter过滤
代码:
ArrayList<Employee> list=new ArrayList<>();
list.add(new Employee("小王", 15000));
list.add(new Employee("小张", 12000));
list.add(new Employee("小李", 18000));
list.add(new Employee("小孙", 20000));
list.add(new Employee("小刘", 25000));
list.add(new Employee("小刘", 25000));
//获取薪资大于15000,forEach终止操作,遍历结果
list.stream()
.filter(e->e.getMoney()>15000)
.forEach(System.out::println);
2,limit限制
代码:
ArrayList<Employee> list=new ArrayList<>();
list.add(new Employee("小王", 15000));
list.add(new Employee("小张", 12000));
list.add(new Employee("小李", 18000));
list.add(new Employee("小孙", 20000));
list.add(new Employee("小刘", 25000));
list.add(new Employee("小刘", 25000));
//获取集合中前两个输出
list.stream()
.limit(2)
.forEach(System.out::println);
3,skip跳过
代码:
ArrayList<Employee> list=new ArrayList<>();
list.add(new Employee("小王", 15000));
list.add(new Employee("小张", 12000));
list.add(new Employee("小李", 18000));
list.add(new Employee("小孙", 20000));
list.add(new Employee("小刘", 25000));
list.add(new Employee("小刘", 25000));
//跳过集合中前两个输出
list.stream()
.skip(2)
.forEach(System.out::println);
4,distinct去掉重复
注意:存储对象必须实现hashCode()和equals()方法,用这两个方法判断是否重复,先调用哪个hashCode方法,如果该方法的返回值与存储其他数据一致,在调用equals比较
代码:
ArrayList<Employee> list=new ArrayList<>();
list.add(new Employee("小王", 15000));
list.add(new Employee("小张", 12000));
list.add(new Employee("小李", 18000));
list.add(new Employee("小孙", 20000));
list.add(new Employee("小刘", 25000));
list.add(new Employee("小刘", 25000));
list.stream()
.distinct()
.forEach(System.out::println);
5,sorted排序
代码:
ArrayList<Employee> list=new ArrayList<>();
list.add(new Employee("小王", 15000));
list.add(new Employee("小张", 12000));
list.add(new Employee("小李", 18000));
list.add(new Employee("小孙", 20000));
list.add(new Employee("小刘", 25000));
list.add(new Employee("小刘", 25000));
list.stream()
.sorted((e1,e2)->Double.compare(e1.getMoney(), e2.getMoney()))
.forEach(System.out::println);
6,map映射操作
简介:将当前Stream中的每个元素都映射转换为另一个元素,从而得到一个新的Stream
代码:
ArrayList<Employee> list=new ArrayList<>();
list.add(new Employee("小王", 15000));
list.add(new Employee("小张", 12000));
list.add(new Employee("小李", 18000));
list.add(new Employee("小孙", 20000));
list.add(new Employee("小刘", 25000));
list.add(new Employee("小刘", 25000));
list.stream()
.map(e->e.getName())
.forEach(System.out::println);
7,parallel并行流
简介:采用多线程 效率高
代码:
ArrayList<Employee> list=new ArrayList<>();
list.add(new Employee("小王", 15000));
list.add(new Employee("小张", 12000));
list.add(new Employee("小李", 18000));
list.add(new Employee("小孙", 20000));
list.add(new Employee("小刘", 25000));
list.add(new Employee("小刘", 25000));
list.stream().parallel()
.forEach(System.out::println);
5.终止操作
1,forEach遍历
代码:
ArrayList<Employee> list=new ArrayList<>();
list.add(new Employee("小王", 15000));
list.add(new Employee("小张", 12000));
list.add(new Employee("小李", 18000));
list.add(new Employee("小孙", 20000));
list.add(new Employee("小刘", 25000));
list.add(new Employee("小刘", 25000));
list.stream().forEach(System.out::println);
2,min最小值
代码:
ArrayList<Employee> list=new ArrayList<>();
list.add(new Employee("小王", 15000));
list.add(new Employee("小张", 12000));
list.add(new Employee("小李", 18000));
list.add(new Employee("小孙", 20000));
list.add(new Employee("小刘", 25000));
list.add(new Employee("小刘", 25000));
Optional<Employee> min = list.stream().min((o1,o2)->Integer.compare(o1.getMoney(), o2.getMoney()));
System.out.println(min.get());
3,max最大值
代码:
ArrayList<Employee> list=new ArrayList<>();
list.add(new Employee("小王", 15000));
list.add(new Employee("小张", 12000));
list.add(new Employee("小李", 18000));
list.add(new Employee("小孙", 20000));
list.add(new Employee("小刘", 25000));
list.add(new Employee("小刘", 25000));
Optional<Employee> max = list.stream().max((e1,e2)->Integer.compare(e1.getMoney(), e2.getMoney()));
System.out.println(max.get());
4,count数量
代码:
//薪资大于20000的人数
ArrayList<Employee> list=new ArrayList<>();
list.add(new Employee("小王", 15000));
list.add(new Employee("小张", 12000));
list.add(new Employee("小李", 18000));
list.add(new Employee("小孙", 20000));
list.add(new Employee("小刘", 25000));
list.add(new Employee("小刘", 25000));
long count = list.stream().filter(o -> o.getMoney()>20000).count();
System.out.println(count);
5,reduce规约
代码:
//所有员工薪资和
ArrayList<Employee> list=new ArrayList<>();
list.add(new Employee("小王", 15000));
list.add(new Employee("小张", 12000));
list.add(new Employee("小李", 18000));
list.add(new Employee("小孙", 20000));
list.add(new Employee("小刘", 25000));
list.add(new Employee("小刘", 25000));
Optional<Double> sum = list.stream()
.map(e->e.getMoney())
.reduce((x,y)->x+y);
System.out.println(sum.get());
6,collect收集
代码:
//获取所有的员工姓名,封装成一个list集合
ArrayList<Employee> list=new ArrayList<>();
list.add(new Employee("小王", 15000));
list.add(new Employee("小张", 12000));
list.add(new Employee("小李", 18000));
list.add(new Employee("小孙", 20000));
list.add(new Employee("小刘", 25000));
list.add(new Employee("小刘", 25000));
List<String> names = list.stream()
.map(e->e.getName())
.collect(Collectors.toList());
for (String string : names) {
System.out.println(string);
}
四、新时间API
1. 简介
之前时间API存在线程安全问题,设计混乱,顾重新编写的新时间类
1.验证: 之前jdk提供的时间类,在多线程环境下是不安全的(下面程序会崩溃)
SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMdd");
ExecutorService pool = Executors.newFixedThreadPool(10);
Callable<Date> callable=new Callable<Date>() {
@Override
public Date call() throws Exception {
return sdf.parse("20200525");
}
};
List<Future<Date>> list=new ArrayList<>();
for(int i=0;i<10;i++) {
Future<Date> future=pool.submit(callable);
list.add(future);
}
for (Future<Date> future : list) {
System.out.println(future.get().toLocaleString());
}
pool.shutdown();
2. 新时间API相关类
1.LocalDate 与 LocalDateTime
- 作用: 代替Date
- 方法:
now():获取当前时间,静态方法
of():获取指定时间,静态方法
getYear():获取年
getMonthValue():获取月
getDayOfMonth():获取日
plusXXX():添加
minusXXX():减少
atZone(ZoneId zoneId):将时间转换为指定时区的时间
format(DateTimeFormatter dtf):将时间转换为指定格式的字符串
parse(CharSequence text, DateTimeFormatter formatter):将指定格式的字符串转换为时间
代码:
//1创建本地时间
LocalDateTime localDateTime=LocalDateTime.now();
//LocalDateTime localDateTime2=LocalDateTime.of(year, month, dayOfMonth, hour, minute)
System.out.println(localDateTime);
System.out.println(localDateTime.getYear());
System.out.println(localDateTime.getMonthValue());
System.out.println(localDateTime.getDayOfMonth());
//2添加两天
LocalDateTime localDateTime2 = localDateTime.plusDays(2);
System.out.println(localDateTime2);
//3减少一个月
LocalDateTime localDateTime3 = localDateTime.minusMonths(1);
System.out.println(localDateTime3);
2.DateTimeFormatter
- 作用: 代替SimpleDateFormat
- 方法:
ofPattern("时间格式"):设定时间格式
代码:
DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyyMMdd");
ExecutorService pool = Executors.newFixedThreadPool(10);
Callable<LocalDate> callable=new Callable<LocalDate>() {
@Override
public LocalDate call() throws Exception {
return LocalDate.parse("20200525",dtf);
}
};
List<Future<LocalDate>> list=new ArrayList<>();
for(int i=0;i<10;i++) {
Future<LocalDate> future=pool.submit(callable);
list.add(future);
}
for (Future<LocalDate> future : list) {
System.out.println(future.get());
}
pool.shutdown();
3.ZoneId:时区
方法:
public static Set<String> getAvailableZoneIds():获取所有时区
public static ZoneId systemDefault():获取系统默认时区
4.Instant:时间戳
方法:
public static Instant now():获取当前时间
public long toEpochMilli():获取当前时间与1970年1月1日00:00:00:000的时间差,单位毫秒
public Instant plusSeconds(long secondsToAdd):减数当前时间的秒数
5.时间转换:
(1) Date —>Instant---->LocalDateTime
代码:
Date date=new Date();
Instant instant = date.toInstant();
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
(2) LocalDateTime —>Instant---->Date
代码:
Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
Date from = Date.from(instant);
System.out.println(from);