lambda
案例
匿名内部类
public void test(){
Comparator<Integer> com = new Comparator<Integer>(){
public int compare(Integer o1,Integer o2){
return Integer.compare(o1,o2)
}
}
TreeSet<Integer> ts = new TreeSet<>(com);
}
简化
public void test(){
Comparator<Integer> com= (x,y)->Integer.compare(x,y);
TreeSet<Integer> ts = new TreeSet<>(com);
}
List过滤
public class Employee{
private int salary;
private int age;
private String name;
public Employee(String name,int age,int salary){
this.name = name;
this.age = age;
this.salary = salary;
}
}
public class Test{
List<Employee> list = Arrays.asList(
new Employee("xx",18,2000),
new Employee("xx",19,3000),
new Employee("xx",20,4000),
new Employee("xx",21,5000),
new Employee("xx",22,6000)
);
// 年龄大于20
// 如果有多个过滤,要写多次过滤方法
pulic List<Person> filterEmployee(List<Employee> list){
List<Employee> result = new ArrayList<>();
for(Employee emp : emps){
if(emp.getAge()>=20){
result.add(emp);
}
}
return result;
}
}
化简
方法一
- 策略设计模式
public interface MyPerdicate<T>{
public boolean test(T t);
}
public class FilterEmployeeByAge implements MyPerdicate<Employee>{
public boolean test(Employee t){
return t.getAge() >= 20;
}
}
public class Test{
List<Employee> employees = Arrays.asList(
new Employee("xx",18,2000),
new Employee("xx",19,3000),
new Employee("xx",20,4000),
new Employee("xx",21,5000),
new Employee("xx",22,6000)
);
public List<Employee> filterEmployee(List<Employee> list,MyPerdicate<Employee> mp){
List<Employee> result = new ArrayList<>();
for(Employee emp : emps){
if(mp.test(emp)){
result.add(emp);
}
}
return result;
}
public void test(){
List<Employee> list = filterEmployee(employees,new FilterEmployeeByAge());
}
}
方法二
- 匿名内部类
List<Employee> list = filterEmployee(employees,new MyPerdicate(){
public boolean test(Employee t){
return t.getSalary() <= 5000
}
});
方法三
- Lambda
List<Employee> list = filterEmployee(employees,(e)-> e.getSalary() <= 5000);
方法四
- stream
employees.stream()
.filter((e)->e.getSalary()>=5000)
.forEach(System.out::println);
语法
-
Lambda
- ->
- 箭头操作符
- 左侧参数列表
- 右侧需要执行的功能 lambda体
- 可以不写数据类型,jvm可以类型推断
- 需要函数式接口支持
- 接口中只有一个抽象方法
- @FunctionInterface
- 检查是否是函数式接口
- ->
-
语法格式
- 无参无返回
- ()->System.out.println(“”);
- 一个参数无返回
- (x)->System.out.println(x);
- x -> System.out.println(x);
- 只有一个参数,()可以省略
- 两个以上参数有返回
- (x,y)->{ return xxx };
- 多条语句需要写{}
- 只有一条语句{} 和return都可以省略
- (x,y)->{ return xxx };
- 无参无返回
// 无参无返回
Runnable r1 = new Runnable(){
public void run(){
System.out.println("");
}
}
Runnable r2 = ()->System.out.println("");
// 一个参数无返回
Consumer<String> com = (x)->System.out.println(x);
com.accept("xxx");
// 两个以上参数有返回
Comparator<Integer> com = (x,y)->{
return Integer.compare(x,y);
};
- @FunctionInterface
// 检查是否是函数式接口
@FunctionInterface
public interface Test{
public bookean test();
}
四大核心函数式接口
-
Consumer:消费型接口
- void accept(T t);
-
Supplier: 供给型接口
- T get();
-
Function<T, R>:函数型接口
- R apply(T t);
-
Predicate:断言型接口
- boolean test(T t);
其他接口
- BiFunction<T,U,R>
- R apply(T t,U u)
- UnaryOperator
- T apply(T t)
- BinaryOperator
- T apply(T t1,T t2)
- BiConsumer<T,U>
- void accept(T t,U u)
- ToIntFunction
- ToLongFunction
- ToDoubleFunction
- IntFunction
- LongFunction
- DoubleFunction
方法引用&构造器引用
- lambda中内容已经有方法实现了,可以使用方法引用
方法引用
- 对象::实例方法名
- 类::静态方法名
- 类::实例方法名
- Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数式列表和返回值类型保持一致
- Lambda 参数列表中第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用 ClassName::method
public void test(){
Consumer<String> com1 = (x)->System.out.println(x);
// 参数列表与返回值类型一直
// Consumer<String> accept 返回值void 参数String x
// System.out println 返回值 void 参数String x
Consumer<String> com2 = (x)->System.out::println;
Employee emp = new Employee();
Supplier<String> sup1 = ()-> emp.getName();
// Supplier get() 返回值 String 无参
// Employee getName() 返回值 String 无参
Supplier<String> sup2 = ()-> emp::getName;
Comparator<Integer> com1 = (x,y)->Integer.compare(x,y);
Comparator<Integer> com2 = Integer::compare;
// 第一个参数是实例方法的调用者 第二个是实例方法的参数,可以用ClassName::method
BiPredicate<String,String> bp1 = (x,y)->x.equals(y);
BiPredicate<String,String> bp2 = String::equals;
}
构造器引用
- ClassName::new
- 需要调用的构造器的参数列表要与函数式接口中抽象方法参数列表保持一致!
Supplier<Employee> sup1 = ()->new Employee();
// 自动匹配对应参数的构造器
Supplier<Employee> sup2 = Employee::new;
// Employee(Integer num)
Function<Integer,Employee> fun1 = (x)-new Employee(x);
Function<Integer,Employee> fun2 = Employee::new
数组引用
- Type::new
Function<Integer,String[]> fun1 = x->new String[x];
Function<Integer,String[]> fun2 = x->String[]::new;
Stream Api
创建
//1.可以通过 Collection 系列集合提供的 stream() 或 paralleStream()
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//2.通过 Arrays 中的静态方法 stream() 获取数组流
Employe[] emps = new Employe[10];
Stream<Employe> stream2 = Arrays.stream(emps);
//3.通过 Stream 类中的静态方法 of()
Stream<String> stream3 = Stream.of("aa", "bb", "cc");
//4.创建无限流
//迭代
Stream<Integer> stream4 = Stream.iterate(0, x -> x + 2);
stream4.limit(10).forEach(System.out::println);
//生成
Stream<Double> stream5 = Stream.generate(() -> Math.random());
stream5.limit(10).forEach(System.out::println);
筛选与切片
- forEach
- stream内部迭代
- filter
- limit
- skip
- distinct
// filter 中间操作
// forEach 终止操作 惰性执行
list.stream().filter(e->e.getAge()>20).forEach(System.out::println);
// limit 中间操作 短路
limit.stream().filter(e->e.getAge()>20).limit(2).forEach(System.out::println);
// skip 中间操作
limit.stream().filter(e->e.getAge()>20).skip(2).forEach(System.out::println);
// distinct hashCode equals去重
limit.stream().filter(e->e.getAge()>20).skip(2).distinct().forEach(System.out::println);
映射
- map
- flatMap
- 将每个元素变成一个流,再将所有流练车一个流
// map 函数应用到每个元素并生成新的集合
list1.stream().map(str->str.toUpperCase()).forEach(System.out::println);
list2.stream().map(emp->emp::getName).forEach(System.out::println);
// flatMap
public static Stream<Character> filterCharacter(String str){
List<Character> list = new ArrayList<>();
for(Character ch : str.toCharArray()){
list.add(ch);
}
return list.stream();
}
public void test(){
// flatMap 将多个流整合成一个流
list.stream().flatMap(Test::filterCharacter).forEach(System.out::println);
]
排序
- sorted
// 自然排序
list.stream.sorted().forEach(System.out::println);
// 定制排序
list.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);
查找与匹配
- allMatch
- anyMatch
- noneMatch
- findFirst
- findAny
- count
- max
- min
// allMatch
// 是否匹配所有元素
boolean flag = list.stream().allMatch(e->e.getStatus().equals("xx"));
// anyMatch
// 是否至少匹配一个元素
boolan flag2 = list.stream().anyMatch(e->e.getStatus().equals("xx"));
// noneMatch
// 是否没有匹配所有元素
boolean flag3 = list.stream().noneMatch(e->e.getStatus().equals(""));
// findFirst
// 获取第一个元素
Optional<Employee> op1 = list.stream().sorted((e1,e2)->Double.compare(e1.getSalary(),e2.getSalary())).findFirst();
// findAny
// 返回任意一个元素
Optional<Employee> op2 = list.stream().filter(e->e.getStatus().equals("")).findAny();
// count
Long count = list.stream().count();
// max
Optional<Employee> op3 = list.stream().max((e1,e2)-> Double.compare(e1.getSalaary(),e2.getSalary()));
// min
Optional<Double> op4 = list.stream().map(Employee::getSalary).min( Double::compare);
归约与收集
- reduce
- collect
- Collectors.toList
- Collectors.toSet
- Collectors.toCollection
- Collectors.toCollection(HashSet::new)
- Collectors.countiong
- Collectors.averagingDouble
- list.stream().Collectors.averagingDouble(Employee::getSalary)
- 按工资获取平均值
- Collectors.summingDouble
- list.stream().Collectors.summingDouble(Employee::getSalary)
- 按工资获取总和
- Collectors.maxBy
- list.stream().Collectors.maxBy((e1,e2)->Double.compare(e1.getSalary(),e2.getSalary()))
- 按工资获取最大的对象
- Collectors.minBy
- list.stream().Collectors.minBy((e1,e2)->Double.compare(e1.getSalary(),e2.getSalary()))
- 按工资获取最小的对象
- Collectors.groupingBy
- Map<Status,List> map = list.stream().collect(Collectors.groupingBy(Employee::getStatus))
- 多级分组
- Collectors.partitioningBy
- 分区
- Collectors.summarizingDouble
- DoubleSummaryStatistics dss = list.stream().collect(Collectors.summarizingDouble(Employee::getSalary))
- dss.getSum()
- dss.getAverage()
- dss.getMax()
- DoubleSummaryStatistics dss = list.stream().collect(Collectors.summarizingDouble(Employee::getSalary))
- Collectors.joining
- 连接
- String str = list.stream().map(Employee::getName).collect(Collectors.joining(“,”));
// reduce
// 将流中元素反复结合起来,得到一个值
// 前一次操作值x与当前元素y累加
// 0 为起始值
Integer sum = list1.stream().reduce(0,(x,y)->x+y);
// op.get()
OPtional<Double> op = list2.stream().map(Employee::getSalary).reduce(Double::sum);
// collect
// 收集
list = list.stream().map(Employee::getName).collect(Collectors.toList());
// 多级分组
Map<Status,Map<String,List<Employee>>> map1 = list.stream().collect(Collectors.groupingBy(Employee::getStatus,Collectors.groupingBy((e)->{
if(e.getAge()<=35){
return "青年";
}else{
return "老年";
}
})));
// 分区
Map<Boolean,List<Employee>> map2 = list.stream().collect(Collectors.partitioningBy(e-e.getSalary()>8000));
并行流
Fork/Join框架
- RecursiveTask
- 有返回值的任务
- RecursiveAction
- 没有返回值的任务
public class ForkJoinCalculate extends RecursiveTask<Long>{
private static final long serialVersionUID = xxxxL;
private long start;
private long end;
private static final long THRESHOLD = 10000;
public ForkJoinCalculate(long start,long end){
this.start = start;
this.end = end;
}
protected Long compute(){
long length = end - start;
if(length<=THRESHOLD){
long sum = 0;
for(long i=start;i<=end;i++){
sum += 1;
}
}else{
long mid = (start+end)/2
ForkJoinCalculate left = new ForkJoinCalculate(start,mid);
left.fork();//拆分子任务,并压入线程
ForkJoinCalculate right = new ForkJoinCalculate(mid+1,end);
left.fork();//拆分子任务,并压入线程
return left.join()+right.join();
}
}
}
public class Test{
public void test(){
Instant start = Instant.now();
// ForkJoin需要ForkJoinPool支持
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<Long> task = new ForkJoinCalculate(0,100000000L);
Long sum = pool.invoke(task);
Instant end = Instant.end();
// 耗费时间
// Duration.between(start,end).toMillis()
}
}
并行流
LongStream.rangeClosed(0,1000000000000L)
.parallel()// 开启并行流
.reduce(0,Long::sum);
Optional
- Optional.of(T t)
- 创建Optional实例
- Optional.empty()
- Optional.ofNullable(T t)
- 如果T为空,创建一个空对象
- isPresent()
- orElse(T t)
- 有值就是原值
- 没有值就是t
- orElseGet(Supplier s)
- 同上
- map(Function f)
- 如果有值,对其处理,并返回处理后的Optional
- flatMap(Function mapper)
- 返回值必须是optional
- get()
- 获取内部的对象实例
// 如果of(null),会空指针异常
Optional<Employee> op1 = Optional.of(new Employee());
Employee emp = op1.get();
// 创建一个空实例
Optional<Employee> op2 = Optional.empty();
// 空指针异常
// op2.get();
Optional<Employee> op3 = Optional.ofNullable(null);
// 判断有没有值
if(op.isPresent()){
// 没有值 抛出异常
Employee emp = op3.get();
}
// 有值,则返回,没有值,则返回默认值
Employee emp = op.orElse(new Employee());
// Employee emp = op.orElseGet(()->new Employee())
// map
Optional<Employee> op = Optional.ofNullable(new Employee());
Optional<String> str = op.map(e->e.getName());
// flatMap
Optional<String> str2 = op.flatMap(e-> Optional.of(e.getName()));
接口默认方法
- 多个接口相同默认方法
- 接口名.super.方法名()
//类优先原则
//父类和接口相同方法,优先父类
public interface MyFun{
default String getName(){
return "xxx";
}
public static void show(){
return "xxx";
}
}
public class MyClass{
public String getName(){
return "xxx";
}
}
public class SubClass extends MyClass implements MyFun{
public static void main(String[] args){
// 类优先原则
SubClass sub = new SubClass();
sub.getName();// MyClass里面优先
MyFun.show(); // 接口中的静态方法
}
/**
public String getName(){
// MyFun.super.getName()
return "xxx";
}
*/
}
时间api
传统时间
- 线程不安全
//有问题,线程不安全,运行报错
public staic void main(String[] args) throws Exception{
SimpleDateFormat sdf = new SimpleDateFormate("yyyyMMdd");
Callable<Date> task = new Callable<Date>(){
public Date call() throws Exception{
return sdf.parse("20161218");
}
};
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Future<Date>> results = new ArrayList<>();
for(int i=0;i<10;i++){
results.add(pool.submit(task));
}
for(Future<Date> future : results){
System.out.println(future.get());
}
}
- 传统解决方法
private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>(){
protected DateFormat initialValue(){
return new SimpleFateFormat("yyyyMMdd");
}
}
public static Date convert(String source)throws ParseException{
return df.get().parse(source);
}
public staic void main(String[] args) throws Exception{
// SimpleDateFormat sdf = new SimpleDateFormate("yyyyMMdd");
Callable<Date> task = new Callable<Date>(){
public Date call() throws Exception{
return convert("20161218");
}
};
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Future<Date>> results = new ArrayList<>();
for(int i=0;i<10;i++){
results.add(pool.submit(task));
}
for(Future<Date> future : results){
System.out.println(future.get());
}
pool.shutdown();
}
新时间方法
本地时间
- 线程安全
- LocalDate
- LocalTime
- LocalDateTime
public staic void main(String[] args) throws Exception{
//DateTimeFormatter dft = DateTimeFormatter.ISO_LOCAL_DATE;
DateTimeFormatter dft = DateTimeFormatter.ofPattern("yyyyMMdd");
Callable<LocalDate> task = new Callable<LocalDate>(){
public LocalDate call() throws Exception{
return LocalDate.parse("20161218",dtf);
}
};
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Future<Date>> results = new ArrayList<>();
for(int i=0;i<10;i++){
results.add(pool.submit(task));
}
for(Future<Date> future : results){
System.out.println(future.get());
}
pool.shutdown();
}
LocalDateTime dt1 = LocalDateTime.now();
LocalDateTime dt2 = LocalDtaeTime.of(2015,10,19,13,22,33);
// 时间加
LocalDateTime dt3 = dt1.pluseYears(2);
// 时间减
LocalDateTime dt4 = dt1.minusMonths(2);
dt1.getYear();
dt1.getMonthValue();
dt1.getDayOfMonth();
dt1.getHour();
dt1.getMinute();
dt1.getSecond();
时间戳
- 记录时间
- Instant start = Instant.now();//默认获得UTC时区
- Instant end = Instant.now();
- 可以用于计时时间差
- Instant start = Instant.now();//默认获得UTC时区
- 统计
- Duration
- 两个时间之间的间隔
- LocalTime Instant都可
- Duration d = Duration.between(start,end)
- d.getSeconds()
- d.toMillis();
- Period
- 两个日期时间的间隔
- LocalDate
- Period period = Period.between(ld1,ld2);
- p.getYears()
- p.getMonths()
- p.getDays()
- Duration
//从1970-1-1 00:00:00到某个时间点的毫秒值
Instant ins = Instant.now();
// 设置时区偏移
OffsetDateTime odt = ins.atOffset(ZoneOffset.ofHours(8));
ins.toEpochMilli();
// 从元年开始增加秒
Instant ins2 = Instant.ofEpochSecond(1000);
时间矫正器
- TemporalAdjuster
- TemporalAdjusters
LocalDateTime dt1 = LocalDateTime.now();
// 指定当月几号
LocalDateTime dt2 = dt1.withDayOfMonth(10);
// 下一个周日
LocalDateTime dt3 = dt1.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
//自定义下一个工作日
LocalDateTime dt4 = dt1.with((l) -> {
LocalDateTime ldt = (LocalDateTime)l;
// 获取周几
DayOfWeek dow = ldt.getDatOfWeek();
// 周五
if(dow.equals(DayOfWeek.FRIDAY)){
// 加3天
return ldt.plusDays(3);
// 周六
}else if(dow.equals(DayOfWeek.SATURDAY)){
return ldt.plusDays(2);
}else{
return ldt.plusDays(1);
}
});
格式化时间/日期
- DateTimeFormatter
- ISO_DATE
- ISO_DATE_TIME
// 默认ISO标准
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
LocalDateTime ldt = LocalDateTime.now();
String strDate = ldt.format(dtf);
// 自定义格式
DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyyMMdd");
String strDate2 = dtf2.format(ldt);
// 转化回LocalDateTime
LocalDateTime newDate = ldt.parse(strDate2,dtf2);
时区处理
- zoneId
- ZonedDate
- ZonedTime
- ZonedDateTime
// 获取所有时区
Set<String> set = ZoneId.getAvailableZoneIds();
set.forEach(System.out::println);
// 指定时区
LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Europe/Talinn"));
// 换时区
ldt.atZone(ZoneId.of("Europe/Talinn"));
重复注解和类型注解
重复注解
- @Repeatable(xxx.class)
public class Test{
@MyAnnotation(“xx1‘)
@MyAnnotation(“xx2‘)
public void show(){
}
public void test(){
Class<Test> clazz = Test.class;
Method m1= clazz.getMethod("show");
MyAnnotations[] ma = m1.getAnnotationsByType(MyAnnotations.class);
for(MyAnnotations myAnnotations:ma){
// myAnnotations.value()
}
}
}
@Repeatable(MyAnnotations.class)
@@Target({TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
@Rentention(RententionPolicy.RUNTIME)
public @interface MyAnnotation{
String value() default "xxx";
}
@@Target({TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
@Rentention(RententionPolicy.RUNTIME)
public @interface MyAnnotations{
MyAnnotiation[] value();
}