一.Lambda 表达式
lambda 表达式,是1.8引入的全新语法特性,该特性可以简化以前的匿名内部类写法,实现把一段代码当做一个参数传递给某个函数。lambda 表达式使用在 函数式接口传参的场景下,也就是说,如果一个方法的参数是一个函数式接口,那么就可以使用lambda表达式。
1.1 语法
函数式接口 对象名 =
( [参数,....] ) -> { } ;
箭头左侧 : 参数列表
箭头右侧 : 方法体
1.2 语法精简
1.3 体验
Runnable 2
1.4 接口回调原理和流程
二.函数式接口
所谓函数式接口就是指一个接口中只有一个抽象方法,函数式接口可以使用@FunctionInterface 注解标注。可以检查一个接口是否为满足函数式语法。
java 提供了 4种非常常见的函数式接口
2.1 消费型
Consumer 接口,抽象方法为 accept 接收参数 无返回。 用于提供消费逻辑重写。
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}
2.2 供给型
Supplier 无参数,有返回一个值,类型由泛型确定。用于提供创建逻辑重写。
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
2.3 函数型
Function<T, R> 有参数有返回值,参数类型 和 返回值类型分别由 T 与 R决定。用于提供处理逻辑重写。
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
}
2.4 断言型
Predicate 接收一个参数,返回boolean 参数类型由 T 确定。用于提供判断逻辑重写。
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
}
**方法引用 **
如果lambda实现的内容已经存在一个现成的方法,这样就不用谢lambda了可以直接使用这个现成的方法。
引用方式:
对象::实例方法
类名::静态方法
类名::实例方法
类名::new 构造器引用
package methodref;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
/**
* 方法引用: 如果一个lambda 所表达是方法有现成的方法实现了,就可以使用这个现成方法
* 如果现有的方法参数和返回值和即将要写的lambda表达一致,可以引用这个现有方法。
* 1. 实例方法引用 对象::实例方法
* 2. 静态方法引用 类名::静态方法
* 3. 类实例方法引用 类名::实例方法
* 4. 类构造器引用 类名::new
*/
public class TestMethodRef {
public static void main(String[] args) {
//实例化list
List<String> list = Arrays.asList("刘德华","景甜");
//1. 对象::实例方法引用
list.forEach( System.out::println );
//2. 类::静态方法引用
list.forEach( WX::show );
System.out.println("==============================================");
List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog("A"));
dogs.add(new Dog("B"));
dogs.add(new Dog("C"));
dogs.add(new Dog("D"));
//3. 类::实例方法引用
dogs.forEach( Dog::show );
//4. 类::new 构造方法引用
Dog dog = createDog(Dog::new);
System.out.println(dog);
}
//供给型接口使用
public static Dog createDog(Supplier<Dog> obj){
System.out.println("aaa");
Dog dog = obj.get();
System.out.println("sss");
return dog;
}
}
//测试类静态方法引用
class WX{
public static void show(String str){
System.out.println(str);
}
}
class Dog{
String name;
public Dog() {
}
public Dog(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
'}';
}
//测试类实例方法引用
public void show(){
System.out.println(this.getName());
}
}
三.Stream 流
3.1 流的概念
流Stream 这里的流是数据操作流,是流程的流,而非传递数据的流。Stream 抽象的是对数据的操作,自己并不存储数据,而是缓存对数据的一系列中间操作,这些操作会延迟执行,直到执行终止操作。事实上每次中间操作都会返回一个新的流。一个流一旦执行终止操作,将不可再使用了。
3.2 创建流方式
3.2.1 Collection集合
//1. 通过集合创建流 ( 最高频使用 )
Stream<Employee> stream1 = list.stream();
3.2.2 Arrays创建
//2. Arrays工具类创建
String[] arr = {"香蕉","苹果","菠萝"};
Stream<String> stream2 = Arrays.stream(arr);
3.2.3 Stream创建
//3. Stream 静态方法创建 of
Stream<Integer> stream3 = Stream.of(1, 2, 3, 4, 5, 6, 8);
3.3 中间操作
准备数据
//准备数据
List<Employee> list = new ArrayList<>();
list.add( new Employee("小刘","歌手","男",1200.0 ) );
list.add( new Employee("小张","演员","男",1400.0 ) );
3.3.1 filter() 过虑
//list.stream().filter( e-> e.getJob().equals("程序员") ).forEach( e-> System.out.println(e) );
3.3.2 limit() 限制
// 限制条数
//list.stream().limit(3).forEach(e-> System.out.println(e));
3.3.3 skip() 跳过
// 跳过
// list.stream().skip(3).forEach(e-> System.out.println(e));
3.3.4 distinct去重
//去重
// list.stream().distinct().forEach(e-> System.out.println(e));
实体类需要重写equeals()方法
3.3.5 map投影
//投影
//list.stream().map( e-> e.getJob() ).forEach(e-> System.out.println(e));
3.3.5 sorted()排序
list.stream().sorted( (o1, o2) -> { return o2.getSal()-o1.getSal()>0?1:-1;}).forEach(e-> System.out.println(e));
3.4.6 parallel() 并行流
list.stream().filter( (e)->{ return e.getGender().equals("男") ; } ).parallel().forEach(e-> System.out.println(e));
3.4 终止操作
3.4.1 forEach
list.stream().forEach(e-> System.out.println(e));
3.4.2 min()
Optional<Employee> min = list.stream().max((o1, o2) -> o1.getSal() > o2.getSal() ? 1 : -1);
Employee employee = min.get();
Optional 是一种容器,只保存一个值通过 get方法取出值。
3.4.3 max()
Optional<Employee> max = list.stream().max((o1, o2) -> o1.getSal() > o2.getSal() ? 1 : -1);
Employee employee = max.get();
Optional 是一种容器,只保存一个值通过 get方法取出值。
3.4.4 count()
long num = list.stream().filter(e -> e.getGender().equals("男")).count();
3.4.5 collect()
- 收集
List<Employee> collect = list.stream().filter((e) -> e.getJob().equals("演员") && e.getSal() >= 3000).
collect(Collectors.toList());
System.out.println(collect);
Collectors.toList() 收集到一个List集合中
Collectors.toList() 收集到一个Set集合中
- 分组
Map<String, List<Employee>> groups = list.stream().collect(Collectors.groupingBy((e) -> { return e.getJob();}));
for ( String key : groups.keySet()){
System.out.println("-------------"+key+"------------------");
System.out.println( groups.get(key) );
}
Collectors.groupingBy( lambda 给出分组依据 ) 本例中根据 job 分组
四.新的日期API
4.1 引入新日期原因
旧版的日期API主要存在的问题就是 线程不安全,还有就是混乱,体系不完整不全面。
SimpleDateFromat C1alendar 工具存在线程安全性问题。
4.2 新的日期类
LocalDate 日期
// 本地日期(系统时间) now()
LocalDate date = LocalDate.now();
System.out.println(date);
// 本地日期(指定时间) of(year,moonth,day )
LocalDate localDate = LocalDate.of(2021, 5, 13);
System.out.println(localDate);
LocalTime 时间
//本地时间 (系统) now()
LocalTime time = LocalTime.now();
System.out.println(time);
//本地时间(指定) of(hour,minute,second)
LocalTime time2 = LocalTime.of(12,30,50);
System.out.println(time2);
LocalDateTime 日期时间
// 本地日期时间(系统时间)
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime);
// 本地日期时间(指定的)
LocalDateTime localDateTime1 = LocalDateTime.of(2008, 8, 8, 8, 8, 8);
System.out.println(localDateTime1);
Instant 时间戳
标准时刻,不包含时区信息。
Instant now = Instant.now();
System.out.println(now);
ZoneId 时区
// 查询所有时区
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
//zoneIds.forEach(System.out::println);
// 查询本地时区
ZoneId zoneId = ZoneId.systemDefault();
System.out.println(zoneId);
4.3 日期格式化
新日期格式化使用 DateTimeFormatter 格式化工具类。通过静态方法 ofPattern 创建实例并指定格式化模板。
//日期格式化
LocalDateTime date = LocalDateTime.now();
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy/MM/dd");
String mydateStr = date.format(df);
System.out.println(mydateStr);
4.4 新旧日期转换
Date 转 LocalDateTime
System.out.println("--------------------- Date 转 LocalDateTime --------------------------------");
Date oldDate = new Date();
//转成 时间戳
Instant inst = oldDate.toInstant();
// 时间戳 + 时区
LocalDateTime newDate = LocalDateTime.ofInstant(inst, ZoneId.systemDefault() );
System.out.println(newDate);
LocalDateTime 转 Date
System.out.println("-----------------------LocalDateTime 转 Date------------------------------");
Instant inst2 = dateTime.atZone(ZoneId.systemDefault()).toInstant();
Date oldDate2 = Date.from(inst2);
System.out.println(oldDate2);