文章目录
简介
一、Lambda表达式
语法格式
Lambda表达式只能用于函数式接口,即接口里只有一个方法,函数式接口上可加上@FunctionalInterface
注解。
Lambda表达式的参数列表的数据类型可以省略不写,JVM编译器可以通过上下文推断出数据类型,即“类型推断”。
-
无参数,无返回值
Runnable r1 = new Runnable() { @Override public void run() { System.out.println("Hello Java!"); } }; r1.run();
写为Lambda表达式:
Runnable r2 = () -> System.out.println("Hello Lambda!"); r2.run();
-
有一个参数,无返回值(只有一个参数时,小括号可以不写)
Consumer<String> con1 = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; con1.accept("hello");
写为Lambda表达式:
Consumer<String> con2 = (s) -> System.out.println(s); //只有一个参数时,小括号可以不写 //Consumer<String> con2 = s -> System.out.println(s); con2.accept("lambda");
-
有两个以上的参数,有返回值,Lambda体中有多条语句
Comparator<Integer> com1 = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { System.out.println("hello"); return Integer.compare(o1, o2); } }; System.out.println(com1.compare(2, 3));
写为Lambda表达式:
Comparator<Integer> com2 = (o1, o2) -> { System.out.println("lambda"); return Integer.compare(o1, o2); }; System.out.println(com1.compare(2, 3));
-
有两个参数,有返回值(如果只有返回语句,可省略{}和return)
Comparator<Integer> com1 = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1, o2); } }; System.out.println(com1.compare(2, 3));
写为Lambda表达式:
Comparator<Integer> com2 = (x, y) -> Integer.compare(x, y); System.out.println(com2.compare(2, 3));
函数式接口
public static void main(String[] args) {
//Consumer<T> 消费型接口:有参数,无返回值
happy(1000, (m) -> System.out.println("消费" + m + "元"));
//Supplier<T> 供给型接口:有返回值
List<Integer> lists = getNumList(10, () -> (int)(Math.random() * 100));
lists.forEach(System.out::println);
//Function<T, R> 函数型接口:对传参进行处理后返回结果
String s = strHandler("\t\t\t aaa ", (str) -> str.trim());
System.out.println(s);
System.out.println(strHandler("ABCD", (str) -> str.toLowerCase()));
//Predicate<T> 断言型接口:对传参进行判断/过滤
List<String> list = Arrays.asList("hello lambda aa bbb cccccc www ok".split(" "));
List<String> strings = filterStr(list, (s) -> s.length() > 3);
strings.forEach(System.out::println);
}
public static void happy(double money, Consumer<Double> con){
con.accept(money);
}
public static List<Integer> getNumList(int num, Supplier<Integer> sup){
List<Integer> lists = new ArrayList<>();
for (int i = 0; i < num; i++) {
lists.add(sup.get());
}
return lists;
}
public static String strHandler(String str, Function<String, String> fun){
return fun.apply(str);
}
public static List<String> filterStr(List<String> list, Predicate<String> pre){
List<String> strList = new ArrayList<>();
for (String s : list) {
if(pre.test(s)){
strList.add(s);
}
}
return strList;
}
方法引用
//对象::实例方法名
Consumer<String> con = (x) -> System.out.println(x);
Consumer<String> con2 = System.out::println;
//类::静态方法名
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
Comparator<Integer> com2 = Integer::compare;
//类::实例方法名
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
BiPredicate<String, String> bp2 = String::equals;
构造器引用
//无参构造器
Supplier<Employee> emp = () -> new Employee();
Supplier<Employee> emp2 = Employee::new;
//一个参数的构造器
Function<Integer, Employee> emp3 = (x) -> new Employee(x);
Function<Integer, Employee> emp4 = Employee::new;
数组引用
Function<Integer, String[]> fun = (x) -> new String[x];
String[] strs = fun.apply(5);
System.out.println(strs.length);
Function<Integer, String[]> fun2 = String[]::new;
String[] strs2 = fun2.apply(4);
System.out.println(strs2.length);
二、Stream API
创建流
//创建流
//1. Conllection系列的集合可以通过stream()或parallelStream()获取流
//stream()为串行
//parallelStream()为并行
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//2. 数组通过Arrays的静态方法stream()获取流
Employee[] emps = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);
//3. 通过Stream的静态方法of()获取流
Stream<String> stream3 = Stream.of("aa", "bb", "ccc");
//4. 创建无限流
//4.1. 迭代
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
stream4
//中间操作
.limit(10)
//终止操作
.forEach(System.out::println);
//4.2. 生成
Stream.generate(() -> Math.random())
//中间操作
.limit(5)
//终止操作
.forEach(System.out::println);
中间操作
筛选与切片
List<Employee> employees = Arrays.asList(
new Employee("张三", 18, 9999.99),
new Employee("李四", 58, 5555.55),
new Employee("王五", 26, 3333.33),
new Employee("赵六", 36, 6666.66),
new Employee("田七", 12, 8888.88),
new Employee("田七", 12, 8888.88),
new Employee("田七", 12, 8888.88)
);
//中间操作:不会执行任何操作
//filter
Stream<Employee> stream1 = employees.stream()
//过滤
.filter((e) -> {
//没有终止操作时,中间操作不会执行(惰性求值/延迟加载)
System.out.println("中间操作:过滤");
return e.getAge() > 35;
});
//终止操作:一次性执行全部内容,即"惰性求值"
stream1.forEach(System.out::println);
//limit
employees.stream()
//过滤,money大于5000
.filter(e -> {
System.out.println("---money > 5000---");
return e.getMoney() > 5000;
})
//截断,截取2个(截取指定数量后,剩下的不会进行,提高效率)
.limit(2)
//终止操作
.forEach(System.out::println);
//skip
employees.stream()
.filter(e -> e.getMoney() > 5000)
//跳过,跳过前2个元素
.skip(2)
.forEach(System.out::println);
//distinct
employees.stream()
.filter(e -> e.getMoney() > 5000)
.skip(2)
//去重,去除重复元素(按照hashCode()和equals()去除重复元素,所以需要重写hashCode()和equals())
.distinct()
.forEach(System.out::println);
映射
//map
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");
list.stream()
.map((str -> str.toUpperCase()))
.forEach(System.out::println);
System.out.println("------------------------------");
employees.stream()
.map(emp -> emp.getName())
.forEach(System.out::println);
public static void main(String[] args) {
//flatMap
Stream<Stream<Character>> stream = list.stream()
//list的每个元素都放入filterCharacter方法拆成char数组放到一个新的list的流中
.map(TestStream2::filterCharacter);
//遍历流,Stream<Stream<Character>> {[a,a,a],[b,b,b],[c,c,c],[d,d,d]}
stream.forEach((sm) -> {
//遍历流中的流,即Stream<Character> [a,a,a]
sm.forEach(System.out::println);
});
System.out.println("------------------------------");
Stream<Character> stream2 = list.stream()
//整合成一个流 {a,a,a,b,b,b,c,c,c,d,d,d}
.flatMap(TestStream2::filterCharacter);
stream2.forEach(System.out::println);
}
public static Stream<Character> filterCharacter(String str){
List<Character> list = new ArrayList<>();
for (char ch : str.toCharArray()) {
list.add(ch);
}
return list.stream();
}
排序
//sorted():按照默认规则进行排序
List<String> list = Arrays.asList("bbb", "ddd", "aaa", "ccc");
list.stream()
.sorted()
.forEach(System.out::println);
System.out.println("------------------------------");
employees.stream()
//自定义排序规则
.sorted((e1, e2) -> {
//年龄相同按姓名排
if (e1.getAge().equals(e2.getAge())) {
return e1.getName().compareTo(e2.getName());
}else{
//按照年龄排序
return e1.getAge().compareTo(e2.getAge());
}
})
.forEach(System.out::println);
终止操作
查找与匹配
List<Employee> employees = Arrays.asList(
new Employee("张三", 18, 9999.99, Employee.Status.FREE),
new Employee("李四", 58, 5555.55, Employee.Status.BUSY),
new Employee("王五", 26, 3333.33, Employee.Status.VOCATION),
new Employee("赵六", 36, 6666.66, Employee.Status.FREE),
new Employee("田七", 12, 8888.88, Employee.Status.BUSY)
);
//终止操作
//allMatch
boolean b1 = employees.stream()
//检查所有元素是否符合条件,都符合才为true
.allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b1);
//anyMatch
boolean b2 = employees.stream()
//检查所有元素是否有符合条件的元素,有一个符合就为true
.anyMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b2);
//noneMatch
boolean b3 = employees.stream()
//检查所有元素是否都不符合条件,都不符合为true
.noneMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b3);
//findFirst
Optional<Employee> first = employees.stream()
//按照工资排序
.sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
//获取第一个元素
.findFirst();
System.out.println(first.get());
//findAny
Optional<Employee> any = employees.parallelStream()
//过滤出所有空闲状态的员工
.filter((e) -> e.getStatus().equals(Employee.Status.FREE))
//随机获取一个员工
.findAny();
System.out.println(any);
//count
long count = employees.stream()
//查看总数
.count();
System.out.println(count);
//max
Optional<Employee> max = employees.stream()
//按照工资获取最大值
.max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(max.get());
//min
Optional<Double> min = employees.stream()
//提取所有的工资数据
.map(Employee::getSalary)
//获取最小值
.min(Double::compare);
System.out.println(min.get());
归约与收集
//reduce
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
Integer sum = list.stream()
//合并,起始索引为0,执行操作相加
.reduce(0, (x, y) -> x + y);
System.out.println(sum);
Optional<Double> sum2 = employees.stream()
//提取所有的工资数据
.map(Employee::getSalary)
//合并,工资总和
.reduce(Double::sum);
System.out.println(sum2.get());
//collect
List<String> list = employees.stream()
//获取所有名字数据
.map(Employee::getName)
//收集数据,并存放到list中
.collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("-----------------------------");
Set<String> set = employees.stream()
//获取所有名字数据
.map(Employee::getName)
//收集数据,并存放到set中,有去重功能
.collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("-----------------------------");
Set<String> hs = employees.stream()
//获取所有名字数据
.map(Employee::getName)
//收集数据,并存放到HashSet中,有去重功能
.collect(Collectors.toCollection(HashSet::new));
hs.forEach(System.out::println);
//总数
Long count = employees.stream()
.collect(Collectors.counting());
System.out.println(count);
System.out.println("-----------------------------");
//平均值
Double avg = employees.stream()
//工资的平均值
.collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(avg);
System.out.println("-----------------------------");
//总和
Double sum = employees.stream()
.collect(Collectors.summingDouble(Employee::getSalary));
System.out.println(sum);
//最大值
Optional<Employee> max = employees.stream()
.collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(max.get());
//最小值
Optional<Double> min = employees.stream()
.map(Employee::getSalary)
.collect(Collectors.minBy(Double::compare));
System.out.println(min.get());
//分组
Map<Employee.Status, List<Employee>> map = employees.stream()
//按照状态分组
.collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(map);
//多级分组
Map<Employee.Status, Map<String, List<Employee>>> map2 = employees.stream()
//按状态分组后再按照年龄分
.collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
if (e.getAge() <= 35) {
return "青年";
} else if (e.getAge() <= 50) {
return "中年";
} else {
return "老年";
}
})));
System.out.println(map2);
//分区
Map<Boolean, List<Employee>> map = employees.stream()
//满足条件true一个区,不满足条件false一个区
.collect(Collectors.partitioningBy((e) -> e.getSalary() > 8000));
System.out.println(map);
//计算
DoubleSummaryStatistics dss = employees.stream()
.collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(dss.getCount());
System.out.println(dss.getAverage());
System.out.println(dss.getMax());
System.out.println(dss.getMin());
//连接
String s = employees.stream()
.map(Employee::getName)
.collect(Collectors.joining());
// .collect(Collectors.joining(", "));
// .collect(Collectors.joining(", ", "====", "===="));
System.out.println(s);
并行流与顺序流
RecursiveAction没有返回值
RecursiveTask有返回值
三、Optional
四、接口中的默认方法与静态方法
public class Test {
public static void main(String[] args) {
//当某个类继承和实现的类中存在相同的方法时,如果父类中提供了具体实现,优先父类
//如果实现的两个接口都有相同的方法,必须重写其中一个接口的方法
SubClass subClass = new SubClass();
System.out.println(subClass.getName()); //class
MyFun.show();
}
}
interface MyFun{
default String getName(){
return "interface";
}
//接口中可以写静态方法
public static void show(){
System.out.println("interface static method");
}
}
class MyClass{
public String getName(){
return "class";
}
}
class SubClass extends MyClass implements MyFun {
}
五、新时间日期API
LocalDate、LocalTime、LocalDateTime
- LocalDate:日期
- LocalTime:时间
- LocalDateTime:日期时间
三个类用法相同,只是专注点不同。
//获取当前时间
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt); //2020-08-09T22:19:45.912
//获取指定时间,2020-01-01 00:00:00
LocalDateTime ldt2 = LocalDateTime.of(2020, 1, 01, 00, 00, 00);
System.out.println(ldt2); //2020-01-01T00:00
//plusXxx()方法为在当前时间上增加时间
LocalDateTime ldt3 = ldt2.plusYears(2);
System.out.println(ldt3); //2022-01-01T00:00
System.out.println(ldt2.getYear()); //年 2020
System.out.println(ldt2.getMonthValue()); //月 1
System.out.println(ldt2.getDayOfMonth()); //日 1
System.out.println(ldt2.getHour()); //时 0
System.out.println(ldt2.getMinute()); //分 0
System.out.println(ldt2.getSecond()); //秒 0
Instant
Instant:时间戳(以Unix元年(1970-01-01 00:00:00)到某个时间之间时间的毫秒值)
Instant instant = Instant.now(); //默认获取 UTC 时区
System.out.println(instant); //2020-08-09T14:19:45.914Z
//偏移8个小时
OffsetDateTime odt = instant.atOffset(ZoneOffset.ofHours(8));
System.out.println(odt); //2020-08-09T22:19:45.914+08:00
//转成毫秒时间戳
System.out.println(instant.toEpochMilli()); //1596983036271
Instant instant2 = Instant.ofEpochSecond(60);
System.out.println(instant2); //1970-01-01T00:01:00Z
Duration、Period
- Duration:计算两个"时间"的间隔
- Period:计算两个"日期"的间隔
//Duration:计算两个"时间"的间隔
Instant ins1 = Instant.now();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Instant ins2 = Instant.now();
Duration duration = Duration.between(ins1, ins2);
System.out.println(duration.toMillis());
LocalTime lt1 = LocalTime.now();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
LocalTime lt2 = LocalTime.now();
Duration duration2 = Duration.between(lt1, lt2);
System.out.println(duration2.toMillis());
//Period:计算两个"日期"的间隔
LocalDate ld1 = LocalDate.of(2020, 1, 1);
LocalDate ld2 = LocalDate.now();
Period period = Period.between(ld1, ld2);
//相差7个月8天
System.out.println(period.getYears()); //0
System.out.println(period.getMonths()); //7
System.out.println(period.getDays()); //8
时间校正器
TemporalAdjuster:时间校正器
//TemporalAdjuster:时间校正器
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt); //2020-08-10T11:09:16.967
//withXxx():
LocalDateTime ldt2 = ldt.withDayOfMonth(10);
System.out.println(ldt2); //2020-08-10T11:09:16.967
//返回下一个周日的日期时间
LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println(ldt3); //2020-08-16T11:09:16.967
//自定义:返回下一个工作日的日期时间
LocalDateTime ldt5 = ldt.with((l) -> {
LocalDateTime ldt4 = (LocalDateTime) l;
//获取当前为周几
DayOfWeek dow = ldt4.getDayOfWeek();
//如果是周五,日期加上3天
if (dow.equals(DayOfWeek.FRIDAY)) {
return ldt4.plusDays(3);
} else if (dow.equals(DayOfWeek.FRIDAY)) {
//如果是周五,日期加上1天
return ldt4.plusDays(2);
} else {
//其他的加1天
return ldt4.plusDays(1);
}
});
System.out.println(ldt5); //2020-08-11T11:17:36.618
DateTimeFormatter:格式化时间/日期
//DateTimeFormatter:格式化时间/日期
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE;
LocalDateTime ldt = LocalDateTime.now();
//格式化日期
String strDate = ldt.format(dtf);
System.out.println(strDate); //2020-08-10
//自定义:日期格式
DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
String strDate2 = dtf2.format(ldt);
System.out.println(strDate2); //2020年08月10日 11:24:53
//转换为原来的日期
LocalDateTime newDate = ldt.parse(strDate2, dtf2);
System.out.println(newDate); //2020-08-10T11:27:28
ZonedDateTime:时区
//支持的时区
Set<String> set = ZoneId.getAvailableZoneIds();
set.forEach(System.out::println);
//指定时区的日期时间
LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
System.out.println(ldt); //2020-08-10T12:34:06.619
//指定时区的日期时间,返回带时区的日期时间
LocalDateTime ldt2 = LocalDateTime.now();
ZonedDateTime zdt = ldt2.atZone(ZoneId.of("Asia/Tokyo"));
System.out.println(zdt); //2020-08-10T11:36:39.001+09:00[Asia/Tokyo]
六、重复注解与类型注解
注解:MyAnnotation
@Repeatable(MyAnnotations.class) //重复注解需要加上@Repeatable注解修饰,并指定注解的容器
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER}) //注解可加的位置(TYPE_PARAMETER:类型注解)
@Retention(RetentionPolicy.RUNTIME) //注解的生命周期
public @interface MyAnnotation {
String value() default "angenin";
}
注解的容器:MyAnnotations
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) //注解可加的位置
@Retention(RetentionPolicy.RUNTIME) //注解的生命周期
public @interface MyAnnotations {
//MyAnnotation的注解容器
MyAnnotation[] value();
}
测试类:TestAnnotation
public class TestAnnotation {
//@NotNull(类型注解):对象不能为空
private @NotNull Object obj = null;
@MyAnnotation("hello")
@MyAnnotation("world")
public void show(@MyAnnotation("abc") String str){
}
public static void main(String[] args) throws Exception {
Class<TestAnnotation> clazz = TestAnnotation.class;
Method m1 = clazz.getMethod("show");
MyAnnotation[] mas = m1.getAnnotationsByType(MyAnnotation.class);
for (MyAnnotation ma : mas) {
System.out.println(ma.value());
}
}
}
JDK1.8的新特性可能并不完整,按照视频记的笔记,目前正在查漏补缺。