Lambda表达式可以看成是匿名内部类,Lambda允许把函数作为一个方法的参数(函数作为方法的参数),将代码像数据一样传递,使用Lambda表达式可以使代码变得更加简洁紧凑。
左侧是参数->右侧是方法体
形参列表的数据类型会自动推断
如果形参列表为空只需保留()
如果只有一个参数,可以将()省略,
如果执行语句只有一句,且无返回值,{}可以省略,若有返回值,想省略{}则必须同时省略return,且执行语句也保证只有一句
lambda不会单独生成一个内部类文件
lambda表达式若访问了局部变量,则局部变量必须是final的,若是局部变量没有加final关键字,那么系统会自用加,以后再修改局部变量会报错
如果一个接口只有一个抽象方法,则该接口称为函数式接口,函数式接口可以使用lambda表达式,lambda表达式会被匹配带这个抽象方法上。
为了确保你的每一个接口一定达到这个要求,你只需在接口是上添加@Functionallnterface注解,编译器会自动为你检查,多于一个抽象方法会报错。
函数式接口 | 参数类型 | 返回类型 | 说明 |
---|---|---|---|
Consumer 消费型接口 | T | void | void accept(T t);对类型为T的对象应用操作 |
Supplier 供给型接口 | 无 | T | T get(); 返回类型为T的对象 |
Function |
T | R | R apply(T t);对类型为T的对象应用操作,并返回类型为R类型的对象。 |
Predicate 断言型接口 | T | boolean | boolean test(T t);确定类型为T的对象是否满足条件,并返回boolean类型。 |
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/*
* created by 夏晓林 in 2019/8/21/021 at 8:09
* lambda表达式的应用(四个核心函数式接口)
* Consumer消费型接口 有参数没有返回值
* Supplier供给型接口 没有参数有返回值
* Function函数型接口 参数是T返回值是R
* Predicate断言型接口 有参数,返回值是boolean型
*/
public class Demo2 {
public static void main(String[] args) {
happy(1000,
m-> System.out.println("吃烤全羊消费"+m)
);
happy(1000,m->System.out.print("消费"+m));
List nums=getNumbers(10,
()-> new Random().nextInt(100)
);
for (Integer num : nums) {
System.out.println(num);
}
System.out.println(stringOpe("hello",
s-> s.toUpperCase()));
System.out.println(stringOpe("Wo", s->s.toLowerCase()));
List names=new ArrayList<>();
names.add("张三");
names.add("李四");
names.add("王五");
names.add("赵六");
List list=filterString(names,
s-> s.startsWith("张"));
List list1=filterString(names,s->s.equals("张三"));
for (String s : list1) {
System.out.println(s);
}
}
//消费性接口
public static void happy(double money, Consumer consumer){
consumer.accept(money);
}
//供给型接口
public static List getNumbers(int count, Supplier supplier){
List list=new ArrayList<>();
for (int i = 0; i function){
return function.apply(s);
}
//断言型接口
public static List filterString(List list, Predicate predicate){
List list1=new ArrayList<>();
for (String s : list) {
if(predicate.test(s)){
list1.add(s);
}
}
return list1;
}
}
方法引用是lambda的一种简写方式。如果lambda表达式只是调用一个特定的已经存在的方法,则可以使用方法引用
import java.util.Comparator;
import java.util.TreeSet;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;
/*
* created by 夏晓林 in 2019/8/21/021 at 22:21
* 方法引用:如果lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用
* 对象::实例方法
* 类::静态方法
* 类::实例方法
* 类::new
*
*/
public class Demo3 {
public static void main(String[] args) {
//方法引用 对象::方法名
Consumer con=s-> System.out.println(s);
//等价于
Consumer con1=System.out::println;
con.accept("hello");
con1.accept("world");
//类名::静态方法
Comparator comparator=(x,y)->Integer.compare(x, y);
Comparator comparator1=Integer::compare;
TreeSet treeSet=new TreeSet<>(comparator1);
//类名::实例方法名
BiPredicate bpre=(x,y)->x.equals(y);
BiPredicate bpre1=String::equals;
//构造方法引用:
// Supplier sup3=()->new Employee();
// Supplier sup4=Employee::new;
}
}
Stream是java8 中处理数组、集合的抽象概念,他可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API对集合进行操作,就类似于使用SQL执行的数据库查询。也可以使用stream API 来并行执行操作。
Stream API特点:
Stream 自己不会存储元素
Stream不会改变原对象,相反,他们会返回一个持有结果的新Stream
Stream操作时延迟执行的,这意味着他们会等到需要结果的时候才会执行
Stream遵循“做什么而不是怎么去做”的原则。只需要描述需要做什么,而不用考虑程序是怎么实现的。
使用Stream的三个步骤:
Stream的中间操作:
包括:map、filter、distinct、sorted、peek、limit、skip、parallel、sequential、unordered
多个中间操作形成了一个流水线,除非流水线上触发终止操作,否则中间操作不会被执行的,而在终止操作时一次性全部处理,称为“惰性求值”
终止操作:
forEach forEachOrdered toArray rreduce collect min max count anyMatch allMatch noneMatch findFirst findAny iterator
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/*
* created by 夏晓林 in 2019/8/22/022 at 11:23
*/
public class Demo5 {
/*public static void main(String[] args) {
//Stream的创建方法
//Stream.of方法
Stream stream=Stream.of("a","b","c");
//Arrays.stream方法
String[] arr=new String[]{"a","b","c"};
stream =Stream.of(arr);
stream= Arrays.stream(arr);
//集合方法
List list=Arrays.asList(arr);
stream=list.stream();
stream=list.parallelStream();//并行流
//创建无限流
//迭代
Stream stream1=Stream.iterate(0, x->x+2);
stream1.limit(10).forEach(System.out::println);
//生成
Streamstream2=Stream.generate(()->Math.random());
stream2.limit(5).forEach(System.out::println);
}*/
public static void main(String[] args) {
List employees=new ArrayList<>();
employees.add(new Employee("xxx",30,1000,"男"));
employees.add(new Employee("yyy",20,3000,"女"));
employees.add(new Employee("zzz",23,1200,"女"));
employees.add(new Employee("张三",42,2000,"男"));
employees.add(new Employee("李四",19,1900,"男"));
employees.add(new Employee("李四",19,1900,"男"));
//筛选和切片
System.out.println("--------filter排除------");
Stream stream=employees.stream()
.filter(e->e.getAge()>25);
stream.forEach(System.out::println);
System.out.println("---------limit限制个数-----------");
Stream stream1=employees.stream().limit(3);
stream1.forEach(System.out::println);
System.out.println("---------skip跳过元素,返回一个扔掉了前n个元素的流-----------");
Stream stream3=employees.stream().skip(2);
stream3.forEach(System.out::println);
System.out.println("---------distinct筛选通过流所生成元素的equals()去除重复元素-----------");
Stream stream4=employees.stream().distinct();
stream4.forEach(System.out::println);
//映射map--接收Lambda
//将元素转换为其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
System.out.println("-------获取员工姓名--------");
Stream str=employees.stream().map(e->e.getName());
str.forEach(System.out::println);
System.out.println("------转换为大写-------");
List list=Arrays.asList("aaa","bbb","ccc","ddd");
Stream stream2=list.stream().map(String::toUpperCase);
stream2.forEach(System.out::println);
//排序
/*
* sorted()---自然排序
* sorted(Comparator com)----定制排序
* */
System.out.println("------sorted()自然排序--------");
employees.stream().map(Employee::getName)
.sorted()
.forEach(System.out::println);
System.out.println("定制排序");
employees.stream().sorted((x,y)-> {
if(x.getAge()==y.getAge()){
return x.getName().compareTo(y.getName());
}else{
return Integer.compare(x.getAge(),y.getAge() );
}
}
).forEach(System.out::println);
//
System.out.println("---------foreach------------");
employees.stream().forEach(System.out::println);
/*
* allMatch---检查是否匹配所有元素
* anyMatch---检查是否至少匹配一个元素
* noneMatch---检查是否没有匹配的元素
*findFirst---返回第一个元素
* findAny----返回当前流中的任意元素,默认是第一个
* count----返回流中元素的总个数
* max----返回流中的最大值
* min----返回流中最小值
* */
boolean b = employees.stream().allMatch(e -> e.getSex().equals("男"));
boolean b1=employees.stream().anyMatch(e->e.getSex().equals("女"));
boolean b2=employees.stream().noneMatch(e->e.getSex().equals("男"));//没有匹配的元素返回true
System.out.println(b);
System.out.println(b1);
System.out.println(b2);
Optional first = employees.stream().findFirst();
Optional any = employees.stream().findAny();
System.out.println(first.get());
System.out.println(any.get());
Optional max=employees.stream().max((o1,o2)->o1.getAge()-o2.getAge());
System.out.println(max.get());
Optional min=employees.stream().map(Employee::getSalary).min(Double::compareTo);
System.out.println(min.get());
//归纳和收集
/*
* reduce归约 reduce(T identity, BinaryOperator)/reduce(BinaryOperator)
* 可以将流中的元素反复结合起来,得到一个值
* */
List list1=Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer sum=list1.stream().reduce(0,(x,y)->x+y );//第一个参数是初始值,第二个运算法则
System.out.println(sum);
System.out.println("--------------------");
Optional op = employees.stream().map(Employee::getSalary).reduce(Double::sum);
System.out.println(op.get());
/*
* collect---将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中的元素做汇总的方法
*
* */
List list2 = employees.stream().map(Employee::getName).collect(Collectors.toList());
list2.forEach(System.out::println);
System.out.println("--------Set集合----------");
Set set = employees.stream().map(Employee::getName).collect(Collectors.toSet());
set.forEach(System.out::println);
}
}
旧版时间API存在的问题:
java8在java.time包中提供了很多新的API,以下为两个比较重要的API:
LocalDate/LocalTime 和 LocalDateTime 类可以在处理时区不是必须的情况。
LocalDate、LocalTime、LocalDateTime 类的实例是不可变的对象,分别表示使用 ISO-8601日 历系统的日期、时间 、日期和时间。它们提供了简单的日期或时间,不包含与时区相关的信息。
Instant 时间戳 类似以前的Date、Timestamp
它是以Unix元年(传统 的设定为UTC时区1970年1月1日午夜时分)开始 所经历的描述进行运算
TemporalAdjuster : 时间校正器。有时我们可能需要获 取例如:将日期调整到“下个周日”等操作。
TemporalAdjusters : 该类通过静态方法提供了大量的常 用 TemporalAdjuster 的实现。
java.time.format.DateTimeFormatter 类:该类提供了三种 格式化方法:
预定义的标准格式
语言环境相关的格式
自定义的格式
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
/*
* created by 夏晓林 in 2019/8/22/022 at 15:33
*/
public class Demo7 {
/*public static void main(String[] args) {
//当前时间
LocalDateTime ldt=LocalDateTime.now();
System.out.println(ldt);
//其他时间
LocalDateTime ldt2=LocalDateTime.of(2012,10,1,2,3,4);
System.out.println(ldt2);
//加时间
LocalDateTime ldt3=ldt2.plusDays(2);
System.out.println(ldt3);
//减时间
LocalDateTime ldt4=ldt3.minusDays(2);
System.out.println(ldt4);
//获取时间部分
System.out.println(ldt.getYear());
System.out.println(ldt.getMonthValue());
System.out.println(ldt.getDayOfMonth());
System.out.println(ldt.getHour());
System.out.println(ldt.getMinute());
System.out.println(ldt.getSecond());
}*/
public static void main(String[] args) throws Exception{
//时间戳
Instant instant=Instant.now();
System.out.println(instant);
Thread.sleep(1000);
Instant instant1=Instant.now();
long mills= Duration.between(instant, instant1).toMillis();
System.out.println(mills);
//时区
System.out.println(ZoneId.getAvailableZoneIds());
ZoneId zoneId=ZoneId.of("Europe/Berlin");
ZoneId zoneId2=ZoneId.of("Brazil/East");
System.out.println(zoneId.getRules());
System.out.println(zoneId2.getRules());
System.out.println("-----------Date--Instant---LocalDateTime-------");
Date date=new Date();
Instant instant2=date.toInstant();
LocalDateTime localDateTime = instant2.atZone(ZoneId.systemDefault()).toLocalDateTime();
System.out.println(localDateTime);
System.out.println("--------LocalDateTime---Instant----Date--------");
Instant instant3 = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
Date date1 = Date.from(instant3);
System.out.println(date1);
}
}