1. 基础语法
Java8中引用一个新的操作符 “->”,该操作符成为箭头操作符或者lambda操作符,箭头操作符将Lambda拆分成两个部分
左侧:Lambda 表达式的参数列表
右侧:Lambda 表达式中所需要的执行的功能,即 Lambda 体
语法格式:
-
无参,无返回值
需要实现接口的抽象方法。无参,无返回值。
()->System.out.println("Hello Lambda");
//测试
@Test
public void test1(){
//注意:jdk1.8之前局部内部类应用局部变量时局部变量必须是final,jdk1.8之后可以不加final但是默认是final的
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Hello World");
}
};
//优化后
Runnable r1 = ()->System.out.println("Hello Lambda");
r.run();
r1.run();
}
- 有一个参数,无返回值
(x) -> System.out.println(x);
@Test
public void test2(){
//一个参数
Consumer<String> con = (x) -> System.out.println(x);
con.accept("JAVA威武霸气");
}
- 若只有一个参数小括号可以省略不写
x -> System.out.println(x);
- 有两个以上的参数,有返回值,并且lambda体中有多条语句
@Test
public void test3(){
Comparator<Integer> com = (x,y) ->{
System.out.println("函数式接口");
return Integer.compare(x,y);
};
}
- 若lambda体中只有一条语句,return和大括号都可以省略不写
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
- 语法格式,Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出数据类型
函数式接口:lanbda中只有一个抽象方法的接口为函数式接口,可以使用@FunctionalInterface进行修饰
测试
//创建一个函数式接口
public interface MyPredicate<T> {
boolean compare(T t);
}
//方法
public Integer operation(Integer num, MyFun myFun){
return myFun.getValue(num);
}
@Test
public void test5(){
//对一个数进行操作
Integer operation = operation(200, x -> x + 200);
System.out.println(operation);
Integer operation1 = operation(300, x -> x * x);
System.out.println(operation1);
}
2. 内置函数式接口
2.1 消费型接口
public interface Consumer<T> {
void accept(T t);
}
举例:
public class TestLambda3 {
@Test
public void test1(){
happy(20000D,x-> System.out.println(x));
}
public void happy(Double money, Consumer<Double> consumer){
consumer.accept(money);
}
}
2.2 供给型接口
@FunctionalInterface
public interface Supplier<T> {
T get();
}
举例:
@Test
public void test2(){
Double suppy = suppy(() -> 222D);
System.out.println(suppy);
}
public Double suppy(Supplier<Double> supplier){
return supplier.get();
}
2.3 函数型接口
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
举例:
@Test
public void test3(){
String abvcdfd = function("abvcdfd", (x) -> x + "12323232");
System.out.println(abvcdfd);
}
public String function(String str, Function<String,String> function){
return function.apply(str);
}
2.4 断言型接口
public interface Predicate<T> {
boolean test(T t);
}
举例:将满足条件的字符串,放入集合中
@Test
public void test4(){
List<String> list = Arrays.asList("1111","22322","545423232","23232323");
List<String> filter = filter(list, x -> x.length() > 4);
System.out.println(filter);
}
public List<String> filter(List<String> strs, Predicate<String> predicate){
List<String> list = new ArrayList<>();
for (String str : strs) {
if(predicate.test(str)){
list.add(str);
}
}
return list;
}
3. 方法引用和构造器引用
若lambda体中的内容方法已经使用了,我们可以使用“方法引用”
主要有三种语法形式
对象::实例方法名
类::静态方法名
类::实例方法名
①左边函数式接口的参数和返回值要和等号右边的一致。
②若lambda 参数列表中的第一参数是实例方法的调用者,而第二个是实例方法的参数时候,可以使用ClassName:method
3.1 实例方法名
@Test
public void test5(){
Consumer<String> consumer1 = x-> System.out.println(x);
consumer1.accept("11111");
Consumer<String> consumer2 = System.out::println;
consumer2.accept("11111");
}
@Test
public void test6(){
Employee employee = new Employee("张三",12,232323D);
Supplier<String> sup = () -> employee.getName();
System.out.println(sup.get());
Supplier<Integer> age = employee::getAge;
System.out.println(age.get());
}
3.2 静态方法名
@Test
public void test7(){
Comparator<Integer> comparator1 = (x,y)->Integer.compare(x,y);
Comparator<Integer> comparator2 = Integer::compareTo;
}
3.3 实例方法名
@Test
public void test8(){
BiPredicate<String,String> bp1 = (x,y) -> x.equals(y);
BiPredicate<String,String> bp2 = String::equals;
}
3.4 构造器引用
ClassName:new
@Test
public void test9(){
Supplier<Employee> sup = ()->new Employee();
//选用的构造器根据前面需要的决定
Supplier<Employee> supplier = Employee::new;
}
3.5 数组引用
public void test10(){
Function<Integer,String[]> function = (x) -> new String[x];
Function<Integer,String[]> function1 = String[]::new;
String[] apply = function1.apply(20);
System.out.println(apply.length);
}
4. Stream
对数据源、集合、数组等进行一系列流水线式的中间操作,产生一个全新的流,数据源不会改变。
Stream 自己不会存储元素
Stream不会改变源对象。相反,他们会返回一个持有结果的新的Stream
Stream操作是延迟执行的。这意味着他们会等到需要的结果的时候才进行执行
4.1 创建流
1.可以通过Collection系列集合提供stream()或parallelStream
ArrayList<String> strings = new ArrayList<>();
strings.stream();
2.通过Arrays中的静态方法stream()获取数组流
Employee[] employees = new Employee[10];
Stream<Employee> stream = Arrays.stream(employees);
3.通过stream类中的静态方法of()
Stream<String> aaa = Stream.of("aaa", "bbb", "vccc");
4.创建无限流
- 迭代
Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);
iterate.limit(10).forEach(System.out::println);
- 生成
Stream<Double> generate = Stream.generate(() -> Math.random());
generate.limit(20).forEach(System.out::println);
4.2 筛选和切片
fileter–接收Lambda,从流中排除某些元素
Stream<Employee> employeeStream = employees.stream().filter(e -> e.getAge() > 27);
employeeStream.forEach(System.out::println);
注意:生成Stream的中间操作,不会执行任何操作,直到终止操作时才会执行全部内容,即惰性求值
limit–截断流,使其元素不超过给定的数量
employees.stream().filter(e -> {
System.out.println("短路");
return e.getAge() > 27;
}).limit(2).forEach(System.out::println);
skip(n) --跳过元素,返回一个扔掉了前n个元素的流。若流中的元素不足n个,则返回一个空流。与limit互补
employees.stream().filter((e) -> {
return e.getAge() > 27;
}).skip(2).forEach(System.out::println);
distinct–筛选,通过流生成的元素的 hashCode() 和 equals() 去除重复元素
employees.stream().filter((e) -> e.getAge() > 27).distinct().forEach(System.out::println);
4.3 映射
map–接收 Lambda ,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素
List<String> list = Arrays.asList("aaa","bbb","ccc");
list.stream().map(String::toUpperCase).forEach(System.out::println);
employees.stream().map(Employee::getName).forEach(System.out::println);
flatMap–接收一个函数作为参数,将流中每个值都转换成另一个流,然后把所有的流连接成一个流
@Test
void test1() {
List<String> list = Arrays.asList("asdfsdfas","fasdf","fasdf");
Stream<Stream<Character>> streamStream = list.stream().map(TestStreamApi2::filterCharacter);
//这种流里套流的方式,可以直接使用flatMap
streamStream.forEach(st-> st.forEach(System.out::println));
//连接成一个流
list.stream().flatMap(TestStreamApi2::filterCharacter).forEach(System.out::println);
}
public static Stream<Character> filterCharacter(String str){
List<Character> list = new ArrayList<>();
for (char c : str.toCharArray()) {
list.add(c);
}
return list.stream();
}
4.4 排序
sorted()–自然排序(Comparable)
List<String> list = Arrays.asList("aaa","ccc","bbb","eee","fff");
list.stream().sorted().forEach(System.out::println);
sorted(Comparator)–定制排序
employees.stream().sorted((e1,e2)->{
if(e1.getAge()==e2.getAge()){
return Double.compare(e1.getSalary(),e2.getSalary());
}
return Integer.compare(e1.getAge(),e2.getAge());
}).forEach(System.out::println);
4.5 查找与匹配
allMatch–检查是否匹配所有元素
anyMatch–检查是否至少匹配一个元素
noneMatch–检查是否没有匹配所有元素
findFirst–返回第一个元素
findAny–返回当前流中的任意元素
count–返回流中的元素的总个数
max–返回流中的最大值
min–返回流中的的最小值
//allMatch
boolean b = employees.stream().allMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b);
//anyMatch
boolean b1 = employees.stream().anyMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b1);
//noneMatch
boolean b2 = employees.stream().noneMatch(e -> e.getStatus().equals(Employee.Status.AAA));
System.out.println(b2);
//findFirst
Optional<Employee> op = employees.stream().sorted(Comparator.comparingDouble(Employee::getSalary).reversed()).findFirst();
System.out.println(op.get());
//findAny
Optional<Employee> any = employees.stream().filter(e -> e.getStatus().equals(Employee.Status.FREE)).findAny();
System.out.println(any.get());
//count
long count = employees.stream().count();
System.out.println(count);
//max
Optional<Employee> employee = employees.stream().max(Comparator.comparingDouble(Employee::getSalary));
System.out.println(employee.get());
//min
Optional<Double> min = employees.stream().map(Employee::getSalary).min(Double::compare);
System.out.println(min.get());
4.6 归约
List<Integer> list = Arrays.asList(1,2,5,7,8,32);
Integer sum = list.stream().reduce(0, (x, y) -> x + y);
System.out.println(sum);
System.out.println("------------------------");
Optional<Double> reduce = employees.stream().map(Employee::getSalary).reduce(Double::sum);
System.out.println(reduce.get());
4.7 收集
收集:将流转换为其他格式。接收一个Collecotr接口的实现,用于给Stream中元素做汇总方法
Collector接口中方法的实现决定了如何对流执行收集操作(如:收集到List、Set、Map)。但是Collectors实用类提供了很多静态方法,可以方便的创建常见的收集器实例。
//转换为List
List<String> list = employees.stream().map(Employee::getName).collect(Collectors.toList());
list.forEach(System.out::println);
//转换为Set
Set<String> collect = employees.stream().map(Employee::getName).collect(Collectors.toSet());
HashSet<String> collect1 = employees.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));
//总条数目
Long collect2 = employees.stream().collect(Collectors.counting());
System.out.println(collect2);
//平均值
Double average = employees.stream().collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(average);
//总和
Double collect3 = employees.stream().collect(Collectors.summingDouble(Employee::getSalary));
System.out.println(collect3);
//最大值
Optional<Employee> collect4 = employees.stream()
.collect(Collectors.maxBy(Comparator.comparingDouble(Employee::getSalary)));
System.out.println(collect4);
//获取最小工资
Optional<Double> min = employees.stream().map(Employee::getSalary).min(Double::compare);
System.out.println(min);
分组
Collectors.groupingBy
Map<Employee.Status, List<Employee>> map = employees.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(JSON.toJSONString(map));
//多级分组
Map<Employee.Status, Map<String, List<Employee>>> collect = 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(JSON.toJSONString(collect));
分区
满足条件的分一个区,不满足条件的分一个区
Map<Boolean, List<Employee>> collect = employees.stream().collect(Collectors.partitioningBy(e -> e.getSalary() > 8000));
System.out.println(JSON.toJSONString(collect));
其他
DoubleSummaryStatistics collect = employees.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
double max = collect.getMax();
double average = collect.getAverage();
double min = collect.getMin();
连接字符串
String collect = employees.stream().map(Employee::getName).collect(Collectors.joining(",","===","==="));
System.out.println(collect);
5. 并行流和顺序流
Instant start = Instant.now();
LongStream.rangeClosed(0,100000000000L)
//parallel()并行
.parallel()
.reduce(0,Long::sum);
Instant end = Instant.now();
System.out.println("耗费时间:"+ Duration.between(start,end).toMillis());
6. Optional
Optional 容器类的常用方法
Optional.of(T t):创建一个 Optional 实例
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t):若 t 不为null,创建一个 Optional 实例,否则创建空实例
isPresent() : 判断是否包含值
orElse(T t) : 如果调用对象包含值,返回值,否则返回t
orElseGet(Supplier s) : 如果调用对象包含值,返回该值,否则返回s获取的值
map(Function f):如果有值对其进行处理,并返回处理后的 Optional,否则返回 Optional.empty()
flatMap(Function mapper) :与map类似,要求返回值必须为Optional
7. 接口中的默认方法和静态方法
类优先原则
多实现,有相同实现的方法签名时需要实现
静态方法可以直接使用
8. 时间API
//初始化
LocalDateTime ldt = LocalDateTime.now();
LocalDateTime ldt2 = LocalDateTime.of(2019, 12, 12, 16, 24, 25);
//获取年月日
int dayOfMonth = ldt2.getDayOfMonth();
int dayOfYear = ldt2.getDayOfYear();
//时间加减
LocalDateTime ldt3 = ldt2.plusDays(5);
//计算两个时间差
long between1 = ChronoUnit.YEARS.between(ld1, ld2);
System.out.println(between1);
//TemporalAdjuster : 时间矫正器
//--下个星期日
LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
//下个工作日
LocalDateTime localDateTime = ldt.with(l -> {
LocalDateTime ldt4 = (LocalDateTime) l;
DayOfWeek dow = ldt4.getDayOfWeek();
if (dow.equals(DayOfWeek.FRIDAY)) {
return ldt4.plusDays(3);
} else if (dow.equals(DayOfWeek.SATURDAY)) {
return ldt4.plusDays(2);
} else {
return ldt4.plusDays(1);
}
});
System.out.println("下一个工作日日期:"+localDateTime);
//格式化时间 以前:SimpleDateFormatter 新:DateTimeFormatter
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE;
LocalDateTime localDateTime = LocalDateTime.now();
String format = localDateTime.format(dtf);
System.out.println(format);
//自定义格式化DateTimeFormatter.format()
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
String format1 = dateTimeFormatter.format(localDateTime);
System.out.println(format1);
// 解析
LocalDateTime parse = LocalDateTime.parse(format1, dateTimeFormatter);
System.out.println(parse);
//时区支持
Set<String> set = ZoneId.getAvailableZoneIds();
set.forEach(System.out::println);
LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Aden"));
System.out.println(ldt);
ZonedDateTime zonedDateTime = ldt.atZone(ZoneId.of("Asia/Shanghai"));
System.out.println(zonedDateTime);
9.可重复注解和类型注解
在注解上面加 @Repeatable(MyAnnotations.class)