目录
一、Java8概述
Java8 (又称 JKD1.8) 是 Java 语言开发的一个主要版本。
Oracle公司于2014年3月18日发布Java8 。
- 支持Lambda表达式
- 函数式接口
- 新的Stream API
- 新的日期 API
- 其他特性
二、Lambda表达式
2.1 概念
- Lambda表达式是特殊的匿名内部类,语法更简洁。
- Lambda表达式允许把函数作为一个方法的参数(函数作为方法参数传递),将代码像数据一样传递。
2.2 语法
<函数式接口> <变量名> = (x {]()
//方法体[};
2.3 基本使用
演示案例:
package com.qfedu.jdk8new;
import java.util.Comparator;
public class Test01 {
public static void main(String[] args) {
//1.匿名内部类,定义runnable
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("3333");
}
};
//不带参数的简化
Runnable runnable1 = () -> {
System.out.println("3333");
};
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return 0;
}
};
//带参数的简化 a,b 形参名,可以自由写
Comparator<Integer> comparator1 = (a,b)->{
return 0;
};
}
}
Lambda引入了新的操作符:->(箭头操作符),->将表达式分成两部分:
- 左侧:(参数1,参数2…)表示参数列表
- 右侧:{ }内部是方法体
- 形参列表的数据类型会自动推断。
- 如果形参列表为空,只需保留() 。
- 如果形参只有1个,()可以省略,只需要参数的名称即可。
- 如果执行语句只有一句,且无返回值,{}可以省略,若有返回值,则若想省去{},则必须同时省略return,且执行语句也保证只有一句。
- Lambda不会生成一个单独的内部类文件。
2.4 案例
Usb接口:
@FunctionalInterface
public interface Usb {
void service();
}
TestUsb类:
public class TestUsb {
public static void main(String[] args) {
//匿名内部类
Usb mouse=new Usb() {
@Override
public void service() {
System.out.println("鼠标开始工作了..........");
}
};
Usb fan=()->System.out.println("风扇开始工作了..........");
run(mouse);
run(fan);
}
public static void run(Usb usb) {
usb.service();
}
}
三、函数式接口
3.1 概念
- 如果一个接口只有一个抽象方法,则该接口称之为函数式接口。
- 函数式接口可以使用Lambda表达式,Lambda表达式会被匹配到这个抽象方法上 。
- @FunctionalInterface 注解检测接口是否符合函数式接口规范。
3.2 常见函数式接口
接口 | 参数类型 | 返回类型 | 说明 |
---|---|---|---|
Consumer< T > 消费型接口 | T | void | void accept(T t);对类型为T的对象应用操作 |
Supplier< T > 供给型接口 | 无 | T | T get(); 返回类型为T的对象 |
Function< T,R > 函数型接口 | T | R | R apply(T t);对类型为T的对象应用操作,并返回类型为R类型的对象。 |
Predicate< T > 断言型接口 | T | boolean | boolean test(T t);确定类型为T的对象是否满足条件,并返回boolean类型。 |
案例演示:
package com.qfedu.jdk8new;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
public class Test02 {
public static void main(String[] args) {
//1限定了一个接口中只有一个方法
//2. 一个参数 和返回值
// 有参数 没有返回值
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
Consumer<String> consumer1 = (s) ->{
System.out.println(s);
};
consumer1.accept("ooooo");
// 没有参数 有返回值
Supplier<String> supplier = new Supplier<String>() {
@Override
public String get() {
return "哈哈";
}
};
System.out.println(supplier.get());
// 有参数 有返回值
Function<String,String> function = new Function<String, String>() {
@Override
public String apply(String s) {
return s+"123";
}
};
Function<String,String> function1 = (a) -> {
return a+"123";
};
System.out.println(function1.apply("555"));
Predicate<String> predicate = new Predicate<String>() {
@Override
public boolean test(String str) {
if(str==null || str.length()<=0) {
return false;
}
return true;
}
};
Predicate<String> predicate1 = (str) -> {
if(str==null || str.length()<=0) {
return false;
}
return true;
};
}
}
四、方法引用
4.1 概念
- 方法引用是Lambda表达式的一种简写形式。
- 如果Lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用。
常见形式:
- 对象::实例方法
- 类::静态方法
- 类::实例方法
- 类::new
4.2 基本使用
Hero类:
package com.qfedu.jdk8x;
public class Hero {
private Integer id;
private String name;
public Hero() {
}
public Hero(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Hero{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
Test3类:
package com.qfedu.jdk8new;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class Test03 {
public static void main(String[] args) {
// + 对象::实例方法
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
Consumer<String> consumer1 = (s) -> {
// System.out.println(s);
Hero hero = new Hero();
hero.setName(s);
};
Hero hero = new Hero();
Consumer<String> consumer2 = hero::setName;
// + 类::静态方法
Consumer<String> consumer3 =Hero::add;
consumer3.accept("asss");
// + 类::实例方法( 必须 一个地方传入对象)
Consumer<Hero> consumer4 = new Consumer<Hero>() {
@Override
public void accept(Hero hero) {
hero.getId();
}
};
Consumer<Hero> consumer5 =Hero::getId;
consumer5.accept(new Hero());
// + 类::new 用来返回一个对象 Hero:new Hero h = new Hero();
Supplier<Hero> supplier = new Supplier<Hero>() {
@Override
public Hero get() {
return new Hero();
}
};
Supplier<Hero> supplier1 = () -> {
return new Hero();
};
Supplier<Hero> supplier2 = Hero::new;
Hero hero1 = supplier2.get();
}
}
五、Stream
5.1 概念
流(Stream)与集合类似,但集合中保存的是数据,而Stream中保存对集合或数组数据的操作。
5.2 Stream特点
- Stream 自己不会存储元素。
- Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
- Stream 操作是延迟执行的,会等到需要结果的时候才执行。
5.3 Stream使用步骤
创建:
- 新建一个流。
中间操作:
- 在一个或多个步骤中,将初始Stream转化到另一个Stream的中间操作。
终止操作:
- 使用一个终止操作来产生一个结果。该操作会强制之前的延迟操作立即执行,在此之后,该Stream就不能使用了。
5.4 创建Stream
- 通过Collection对象的stream()或parallelStream()方法。
- 通过Arrays类的stream()方法。
- 通过Stream接口的of()、iterate()、generate()方法。
- 通过IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法。
案例演示:
package com.qfedu.jdk8new;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.IntStream;
import java.util.stream.Stream;
//Stream操作1: 获取Stream对象
public class Test04 {
public static void main(String[] args) {
//1.准备一个集合
List<Hero> heroList = new LinkedList<>();
heroList.add(new Hero(1001,"小乔"));
heroList.add(new Hero(1002,"大乔"));
heroList.add(new Hero(1003,"老乔"));
heroList.add(new Hero(1004,"二乔"));
heroList.add(new Hero(1005,"三乔"));
System.out.println(heroList);
System.out.println("==================================");
//获取流
Stream<Hero> stream = heroList.stream();
/* Consumer<Hero> comsumer = (hero) ->{
System.out.println(hero);
};*/
Consumer<Hero> comsumer = System.out::println;
stream.forEach(comsumer);
String[] strings = {"123","456","789","010"};
Stream<String> stream1 = Arrays.stream(strings);
System.out.println("====== 利用Arrays.stream");
Consumer<String> comsumer1 = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
stream1.forEach(comsumer1);
System.out.println("=========通过of方法"); // 通过Stream接口的of()、iterate()、generate()方法。
Stream<Integer> integerStream = Stream.of(1, 2, 3);
integerStream.forEach(System.out::println);
System.out.println("===================of");
// + 通过IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法。
IntStream intStream = IntStream.of(1, 2, 3, 4);
intStream.forEach(System.out::println);
}
}
5.5 中间操作
常见中间操作:
- filter、limit、skip、distinct、sorted
- map
- parallel
案例演示:
package com.qfedu.jdk8x;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class Test5 {
public static void main(String[] args) {
//1.创建集合
List<Hero> heroList = new ArrayList<>();
//2. 添加一些数据
heroList.add(new Hero(1009,"小乔"));
heroList.add(new Hero(1002,"大乔"));
heroList.add(new Hero(1003,"老乔"));
heroList.add(new Hero(1004,"女乔"));
System.out.println(heroList);
// + 通过Collection对象的stream()或parallelStream()方法。
Stream<Hero> stream = heroList.stream();
//(1) filter过滤 过滤掉哪些元素: 如果过滤出来 ,返回true
System.out.println("------filter-------");
Predicate<Hero> predicate = new Predicate<Hero>() {
@Override
public boolean test(Hero hero) {
if(hero.getId()==1001) {
return true;
}
return false;
}
};
//过滤完成后,返回新的stream
stream.filter(predicate).forEach(System.out::println);
System.out.println("原来的"+heroList);
//(2) limit限制
System.out.println("----limit------");
heroList.stream().limit(2).forEach(System.out::println);
//(3) skip跳过
System.out.println("-----skip------");
heroList.stream().skip(2).forEach(System.out::println);
System.out.println("---------sorted---------");
//(4) sorted排序
Comparator<Hero> b = new Comparator<Hero>() {
@Override
public int compare(Hero o1, Hero o2) {
return Integer.compare(o1.getId(),o2.getId());
}
};
heroList.stream().sorted(b).forEach(System.out::println);
//中间操作2 map
System.out.println("---------map--------");
/* Function<Hero,String> cc = new Function<Hero, String>() {
@Override
public String apply(Hero hero) {
return hero.getName();
}
};
*/
Function<Hero,String> cc = (hero) -> {
return hero.getName();
};
heroList.stream()
.map(cc).forEach(System.out::println);
//中间操作3 parallel 采用多线程 效率高
System.out.println("---------map--------");
heroList.parallelStream()
.forEach(System.out::println);
}
}
串行流和并行流:
- 串行流使用单线程。
- 并行流使用多线程,效率更高。
public class Demo7 {
public static void main(String[] args) {
//串行流和并行流的区别
ArrayList<String> list=new ArrayList<>();
for(int i=0;i<5000000;i++) {
list.add(UUID.randomUUID().toString());
}
//串行:10秒 并行:7秒
long start=System.currentTimeMillis();
long count=list.Stream().sorted().count();
//long count=list.parallelStream().sorted().count();
System.out.println(count);
long end=System.currentTimeMillis();
System.out.println("用时:"+(end-start));
}
}
5.6 终止操作
常见终止操作:
- forEach、min、max、count
- reduce、collect
案例演示:
package com.qfedu.jdk8x;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;
public class Test7 {
public static void main(String[] args) {
//1.创建集合
List<Hero> heroList = new ArrayList<>();
//2. 添加一些数据
heroList.add(new Hero(1009,"小乔"));
heroList.add(new Hero(1002,"大乔"));
heroList.add(new Hero(1003,"老乔"));
heroList.add(new Hero(1004,"女乔"));
//1 终止操作 foreach
heroList.stream().forEach(System.out::println);
//2 终止操作 min max count
System.out.println("====================");
Comparator<Hero> cc = new Comparator<Hero>() {
@Override
public int compare(Hero o1, Hero o2) {
return Integer.compare(o1.getId(),o2.getId());
}
};
Optional<Hero> min = heroList.stream().min((o1, o2) -> Integer.compare(o1.getId(), o2.getId()));
System.out.println(min.get());
Optional<Hero> max = heroList.stream().max((o1, o2) -> Integer.compare(o1.getId(), o2.getId()));
System.out.println(max.get());
System.out.println(heroList.stream().count());
// //3 终止操作 reduce 规约 计算id的所有和
// System.out.println("--------reduce---------");
BinaryOperator<Integer> aa = new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer integer, Integer integer2) {
return integer+integer2;
}
};
Optional<Integer> reduce = heroList.stream().map(hero -> hero.getId()).reduce(aa);
System.out.println(reduce.get());
//4 终止方法 collect收集
//获取所有的员工姓名,封装成一个list集合
System.out.println("------collect------");
List<String> collect = heroList.stream().map(hero -> hero.getName()).collect(Collectors.toList());
System.out.println(collect);
}
}
六、新时间API
6.1 概述
之前时间API存在问题:线程安全问题、设计混乱。
本地化日期时间 API:
- LocalDate
- LocalTime
- LocalDateTime
Instant:时间戳。
ZoneId:时区。
Date、Instant、LocalDateTime的转换。
DateTimeFormatter:格式化类。
6.2 LocalDateTime类
表示本地日期时间,没有时区信息
public class Demo2 {
public static void main(String[] args) {
//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);
}
}
6.3 Instant、ZoneId类
Instant表示瞬间;和前面Date类似。
ZoneId表示时区信息。
public class Demo3 {
public static void main(String[] args) {
//1 创建Instant:时间戳
Instant instant=Instant.now();
System.out.println(instant.toString());
System.out.println(instant.toEpochMilli());
System.out.println(System.currentTimeMillis());
//2 添加减少时间
Instant instant2 = instant.plusSeconds(10);
System.out.println(Duration.between(instant, instant2).toMillis());
//3ZoneId
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
for (String string : availableZoneIds) {
System.out.println(string);
}
System.out.println(ZoneId.systemDefault().toString());
//1 Date --->Instant--->LocalDateTime
System.out.println("-------------Date --->Instant---->LocalDateTime-----------");
Date date=new Date();
Instant instant3 = date.toInstant();
System.out.println(instant3);
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant3, ZoneId.systemDefault());
System.out.println(localDateTime);
//2 LocalDateTime --->Instant--->Date
System.out.println("-------------LocalDateTime --->Instant---->Date-----------");
Instant instant4 = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
System.out.println(instant4);
Date from = Date.from(instant4);
System.out.println(from);
}
}
6.4 DateTimeFormatter类(会用)
DateTimeFormatter是时间格式化类。
public class Demo4 {
public static void main(String[] args) {
//创建DateTimeFormatter
DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
//1 把时间格式化成字符串
String format = dtf.format(LocalDateTime.now());
System.out.println(format);
//2 把字符串解析成时间
LocalDateTime localDateTime = LocalDateTime.parse("2020/03/10 10:20:35", dtf);
System.out.println(localDateTime);
}
}