目录
- static?default? lamda表达式?
- 常见的函数式接口
- 方法引用
- Stream总结
- Optinal用法介绍
- 新的日期API LocalDate | LocalTime | LocalDateTime
- CompletableFuture异步编程
- jdk1.8-ForkJoin框架剖析
static?default? lamda表达式?
package com.wanke.microgrid.mgcc;
@FunctionalInterface
public interface NullAnnotation {
//抽象方法
public void getName(String a);
boolean equals(Object obj);
//default方法
default void getAge(){
System.out.println("age");
}
default void getAge1(){
}
//静态方法
static void static1(){
System.out.println("static1");
}
static void static2(){
}
}
package com.wanke.microgrid.mgcc;
public class Test{
public static void main(String[] args) {
String a = "aaaa";
//Lambda表达式
NullAnnotation annotation = (f) -> System.out.println(f);
annotation.getName(a);
//defalut方法属于对象的默认方法
annotation.getAge();
//static属于类的方法
NullAnnotation.static1();
}
}
运行结果:
aaaa
age
static1
@FunctionalInterface标记接口为函数式接口,函数式接口有且只能有一个抽象方法,或许大家会问你不是写了两个抽象方法吗?java.lang.Object根对象有equals方法吧,所以实现该类的时候是不是不必须要实现这个接口(所有的类都是实现java.lang.Object的)。Lambda表达式是基于函数式接口的
常见的函数式接口
package com.wanke.microgrid.mgcc;
import java.util.Comparator;
import java.util.Objects;
import java.util.function.*;
public class Test {
//Consumer消费型接口,有参无返回
static void testConsumer(Integer x, Consumer<Integer> consumer) {
consumer.accept(x);
}
//suplier供给型接口,无参有返回值
static void testSupplier(Supplier<Integer> supplier) {
System.out.println(supplier.get());
}
static Integer getInteger() {
return 2;
}
//函数式接口,有参有返回值
static void testFunction(Integer num, Function<Integer, Integer> function) {
System.out.println(function.apply(num));
}
//断言型接口,有参有返回值,返回值是boolean类型
static void testPredicate(Integer num, Predicate<Integer> predicate) {
System.out.println(predicate.test(num));
}
//介绍部分拓展接口
//BinaryOperator (R apply(T t, U u) ->两个输入,一个输出,而且类型一样)
public static void binaryOperatorCompute(Integer para1, Integer para2, BinaryOperator<Integer> binaryOperator) {
//使用自定义BinaryOperator
System.out.println(binaryOperator.apply(para1, para2));
Comparator<Integer> cpt2 = (x, y) -> Integer.compare(x, y);
//静态方法传入比较器生成BinaryOperator
BinaryOperator<Integer> min = BinaryOperator.minBy(cpt2);
System.out.println(min.apply(para1, para2));
}
//toIntFunction (int applyAsInt(T t, U u) ->两个输入,一个int输出)
public static void testToIntFunction(Integer para1, Integer para2, ToIntBiFunction<Integer, Integer> toIntBiFunction) {
System.out.println(toIntBiFunction.applyAsInt(para1, para2));
}
//BiFunction (R apply(T t, U u) ->两个输入,一个输出)
public static void testBi(Integer para1,Integer para2,BiFunction<Integer, Integer, Integer> biFunction, Function<Integer, Integer> function) {
BiFunction<Integer, Integer, Integer> newBi = biFunction.andThen(function);
System.out.println(newBi.apply(para1,para2));
}
//如何看出输入输出,以BiFunction为例
//源码如下:
//package java.util.function;
//
//import java.util.Objects;
//
//
// @FunctionalInterface
// public interface BiFunction<T, U, R> {
//
//
// R apply(T t, U u);
//
//
// default <V> java.util.function.BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
// Objects.requireNonNull(after);
// return (T t, U u) -> after.apply(apply(t, u));
// }
// }
//函数式接口类型的唯一抽象方法 R apply(T t, U u);显然是量输入一输出,而且是泛型
public static void main(String[] args) {
testConsumer(1, x -> System.out.println(x));
testSupplier(() -> getInteger());
testFunction(100, x -> x + 100);
testPredicate(100, x -> x.equals(100));
binaryOperatorCompute(1, 2, (x, y) -> x + y);
testToIntFunction(3, 4, (x, y) -> x + y + 1);
testBi(5,9,(x,y)->{int z = x+y;return z;},x->x + 3);
}
}
运行结果:
1
2
200
true
3
1
8
17
总之jdk8提供了一种方便的方式让我们传递函数,就像传递参数一样,大家对照着可以看看js的回调。
方法引用
定义了4个方法的Car这个类作为例子,区分Java中支持的4种不同的方法引用。
public static class Car {
public static Car create( final Supplier< Car > supplier ) {
return supplier.get();
}
public static void collide( final Car car ) {
System.out.println( "Collided " + car.toString() );
}
public void follow( final Car another ) {
System.out.println( "Following the " + another.toString() );
}
public void repair() {
System.out.println( "Repaired " + this.toString() );
}
}
第一种方法引用是构造器引用,它的语法是Class::new,或者更一般的Class< T >::new。请注意构造器没有参数。
final Car car = Car.create( Car::new );
final List< Car > cars = Arrays.asList( car );
第二种方法引用是静态方法引用,它的语法是Class::static_method。请注意这个方法接受一个Car类型的参数
cars.forEach( Car::collide );
第三种方法引用是特定类的任意对象的方法引用,它的语法是Class::method。请注意,这个方法没有参数。
cars.forEach( Car::repair );
第四种方法引用是特定对象的方法引用,它的语法是instance::method。请注意,这个方法接受一个Car类型的参数
final Car police = Car.create( Car::new );
cars.forEach( police::follow )
方法和函数都有输入输出,本质上是类似的,所以我们可以引用方法来代替lamda表达式,这样或许好理解一点。
Stream总结
Stream的操作符大体上分为两种:中间操作符和终止操作符
中间操作符
对于数据流来说,中间操作符在执行制定处理程序后,数据流依然可以传递给下一级的操作符。
中间操作符包含8种(排除了parallel,sequential,这两个操作并不涉及到对数据流的加工操作):
1.map(mapToInt,mapToLong,mapToDouble) 转换操作符,把比如A->B,这里默认提供了转int,long,double的操作符。
2.flatmap(flatmapToInt,flatmapToLong,flatmapToDouble) 拍平操作比如把 int[]{2,3,4} 拍平 变成 2,3,4 也就是从原来的一个数据变成了3个数据,这里默认提供了拍平成int,long,double的操作符。
3.limit 限流操作,比如数据流中有10个 我只要出前3个就可以使用。
4.distint 去重操作,对重复元素去重,底层使用了equals方法。
5.filter 过滤操作,把不想要的数据过滤。
6.peek 挑出操作,如果想对数据进行某些操作,如:读取、编辑修改等。
skip 跳过操作,跳过某些元素。
7.sorted(unordered) 排序操作,对元素排序,前提是实现Comparable接口,当然也可以自定义比较器。
终止操作符
数据经过中间加工操作,就轮到终止操作符上场了;终止操作符就是用来对数据进行收集或者消费的,数据到了终止操作这里就不会向下流动了,终止操作符只能使用一次。
1.collect 收集操作,将所有数据收集起来,这个操作非常重要,官方的提供的
Collectors 提供了非常多收集器,可以说Stream 的核心在于Collectors。
2.count 统计操作,统计最终的数据个数。
3.findFirst、findAny 查找操作,查找第一个、查找任何一个 返回的类型为Optional。
4.noneMatch、allMatch、anyMatch 匹配操作,数据流中是否存在符合条件的元素 返回值为bool 值。
5.min、max 最值操作,需要自定义比较器,返回数据流中最大最小的值。
6.reduce 规约操作,将整个数据流的值规约为一个值,count、min、max底层就是使用reduce。
7.forEach、forEachOrdered 遍历操作,这里就是对最终的数据进行消费了。
8.toArray 数组操作,将数据流的元素转换成数组。
parallel会利用多核,但要注意线程安全(利用外部变量时可能会造成线程安全问题,外部变量指的是流操作外面申明的变量)
Optinal用法介绍
//Optional.of()或者Optional.ofNullable():创建Optional对象,差别在于of不允许参数是null,而ofNullable则无限制。
// 参数不能是null
Optional<Integer> optional1 = Optional.of(1);
// 参数可以是null
Optional<Integer> optional2 = Optional.ofNullable(null);
// 参数可以是非null
Optional<Integer> optional3 = Optional.ofNullable(2);
//Optional.empty():所有null包装成的Optional对象:
Optional<Integer> optional4 = Optional.ofNullable(null);
Optional<Integer> optional5 = Optional.ofNullable(null);
System.out.println(optional4 == optional5);// true
System.out.println(optional5 == Optional.<Integer>empty());// true
Object o1 = Optional.<Integer>empty();
Object o2 = Optional.<String>empty();
System.out.println(o1 == o2);// true
//isPresent():判断值是否存在
Optional<Integer> optional6 = Optional.ofNullable(1);
Optional<Integer> optional7 = Optional.ofNullable(null);
// isPresent判断值是否存在
System.out.println(optional6.isPresent() == true);
System.out.println(optional7.isPresent() == false);
Optional<Integer> optional8 = Optional.ofNullable(1);
Optional<Integer> optional9 = Optional.ofNullable(null);
// 如果不是null,调用Consumer
optional8.ifPresent(new Consumer<Integer>() {
@Override
public void accept(Integer t) {
System.out.println("value is " + t);
}
});
// null,不调用Consumer
optional9.ifPresent(new Consumer<Integer>() {
@Override
public void accept(Integer t) {
System.out.println("value is " + t);
}
});
//orElse(value):如果optional对象保存的值不是null,则返回原来的值,否则返回value
Optional<Integer> optional10 = Optional.ofNullable(1);
Optional<Integer> optional11 = Optional.ofNullable(null);
// orElse
System.out.println(optional10.orElse(1000) == 1);// true
System.out.println(optional11.orElse(1000) == 1000);// true
//orElseGet(Supplier supplier):功能与orElse一样,只不过orElseGet参数是一个对象
Optional<Integer> optional12 = Optional.ofNullable(1);
Optional<Integer> optional13 = Optional.ofNullable(null);
System.out.println(optional12.orElseGet(() -> {
return 1000;
}) == 1);//true
System.out.println(optional3.orElseGet(() -> {
return 1000;
}) == 1000);//true
//orElseThrow():值不存在则抛出异常,存在则什么不做,有点类似Guava的Precoditions
Optional<Integer> optional14 = Optional.ofNullable(1);
Optional<Integer> optional15 = Optional.ofNullable(null);
optional14.orElseThrow(()->{throw new IllegalStateException();});
try
{
// 抛出异常
optional15.orElseThrow(()->{throw new IllegalStateException();});
}
catch(IllegalStateException e )
{
e.printStackTrace();
}
//filter(Predicate):判断Optional对象中保存的值是否满足Predicate,并返回新的Optional。
Optional<Integer> optional16 = Optional.ofNullable(1);
Optional<Integer> optional17 = Optional.ofNullable(null);
Optional<Integer> filter1 = optional16.filter((a) -> a == null);
Optional<Integer> filter2 = optional16.filter((a) -> a == 1);
Optional<Integer> filter3 = optional17.filter((a) -> a == null);
System.out.println(filter1.isPresent());// false
System.out.println(filter2.isPresent());// true
System.out.println(filter2.get().intValue() == 1);// true
System.out.println(filter3.isPresent());// false
//map(Function):对Optional中保存的值进行函数运算,并返回新的Optional(可以是任何类型)
Optional<Integer> optional18 = Optional.ofNullable(1);
Optional<Integer> optional19 = Optional.ofNullable(null);
Optional<String> str1Optional = optional18.map((a) -> "key" + a);
Optional<String> str2Optional = optional19.map((a) -> "key" + a);
//flatMap():功能与map()相似,差别请看如下代码。flatMap方法与map方法类似,区别在于mapping函数的返回值不同。map方法的mapping函数返回值可以是任何类型T,而flatMap方法的mapping函数必须是Optional。
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Optional<String>> str3Optional = optional1.map((a) -> {
return Optional.<String>of("key" + a);
});
Optional<String> str4Optional = optional1.flatMap((a) -> {
return Optional.<String>of("key" + a);
});
System.out.println(str3Optional.get().get());// key1
System.out.println(str4Optional.get());// key1
//Optional应用示例
Person person = new Person();
Car car = new Car();
Insurance insurance = new Insurance();
insurance.setName("aa");
car.setInsurance(insurance);
person.setCar(car);
String insuranceName = Optional.ofNullable(person)
.map((p) -> p.getCar())
.map(c -> c.getInsurance())
.map(i -> i.getName()).orElse("unknown");
System.out.println(insuranceName);
}
static class Person {
private Car car;
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
}
static class Car {
private Insurance insurance;
public Insurance getInsurance() {
return insurance;
}
public void setInsurance(Insurance insurance) {
this.insurance = insurance;
}
}
static class Insurance {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
新的日期API LocalDate | LocalTime | LocalDateTime
新的日期API都是不可变的,更使用于多线程的使用环境中
@Test
public void test(){
// 从默认时区的系统时钟获取当前的日期时间。不用考虑时区差
LocalDateTime date = LocalDateTime.now();
//2018-07-15T14:22:39.759
System.out.println(date);
System.out.println(date.getYear());
System.out.println(date.getMonthValue());
System.out.println(date.getDayOfMonth());
System.out.println(date.getHour());
System.out.println(date.getMinute());
System.out.println(date.getSecond());
System.out.println(date.getNano());
// 手动创建一个LocalDateTime实例
LocalDateTime date2 = LocalDateTime.of(2017, 12, 17, 9, 31, 31, 31);
System.out.println(date2);
// 进行加操作,得到新的日期实例
LocalDateTime date3 = date2.plusDays(12);
System.out.println(date3);
// 进行减操作,得到新的日期实例
LocalDateTime date4 = date3.minusYears(2);
System.out.println(date4);
}
@Test
public void test2(){
// 时间戳 1970年1月1日00:00:00 到某一个时间点的毫秒值
// 默认获取UTC时区
Instant ins = Instant.now();
System.out.println(ins);
System.out.println(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli());
System.out.println(System.currentTimeMillis());
System.out.println(Instant.now().toEpochMilli());
System.out.println(Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant().toEpochMilli());
}
@Test
public void test3(){
// Duration:计算两个时间之间的间隔
// Period:计算两个日期之间的间隔
Instant ins1 = Instant.now();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Instant ins2 = Instant.now();
Duration dura = Duration.between(ins1, ins2);
System.out.println(dura);
System.out.println(dura.toMillis());
System.out.println("======================");
LocalTime localTime = LocalTime.now();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
LocalTime localTime2 = LocalTime.now();
Duration du2 = Duration.between(localTime, localTime2);
System.out.println(du2);
System.out.println(du2.toMillis());
}
@Test
public void test4(){
LocalDate localDate =LocalDate.now();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
LocalDate localDate2 = LocalDate.of(2016,12,12);
Period pe = Period.between(localDate, localDate2);
System.out.println(pe);
}
@Test
public void test5(){
// temperalAdjust 时间校验器
// 例如获取下周日 下一个工作日
LocalDateTime ldt1 = LocalDateTime.now();
System.out.println(ldt1);
// 获取一年中的第一天
LocalDateTime ldt2 = ldt1.withDayOfYear(1);
System.out.println(ldt2);
// 获取一个月中的第一天
LocalDateTime ldt3 = ldt1.withDayOfMonth(1);
System.out.println(ldt3);
LocalDateTime ldt4 = ldt1.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
System.out.println(ldt4);
// 获取下一个工作日
LocalDateTime ldt5 = ldt1.with((t) -> {
LocalDateTime ldt6 = (LocalDateTime)t;
DayOfWeek dayOfWeek = ldt6.getDayOfWeek();
if (DayOfWeek.FRIDAY.equals(dayOfWeek)){
return ldt6.plusDays(3);
}
else if (DayOfWeek.SATURDAY.equals(dayOfWeek)){
return ldt6.plusDays(2);
}
else {
return ldt6.plusDays(1);
}
});
System.out.println(ldt5);
}
@Test
public void test6(){
// DateTimeFormatter: 格式化时间/日期
// 自定义格式
LocalDateTime ldt = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
String strDate1 = ldt.format(formatter);
String strDate = formatter.format(ldt);
System.out.println(strDate);
System.out.println(strDate1);
// 使用api提供的格式
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE;
LocalDateTime ldt2 = LocalDateTime.now();
String strDate3 = dtf.format(ldt2);
System.out.println(strDate3);
// 解析字符串to时间
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime time = LocalDateTime.now();
String localTime = df.format(time);
LocalDateTime ldt4 = LocalDateTime.parse("2017-09-28 17:07:05",df);
System.out.println("LocalDateTime转成String类型的时间:"+localTime);
System.out.println("String类型的时间转成LocalDateTime:"+ldt4);
}
// ZoneTime ZoneDate ZoneDateTime
@Test
public void test7(){
LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println(now);
LocalDateTime now2 = LocalDateTime.now();
ZonedDateTime zdt = now2.atZone(ZoneId.of("Asia/Shanghai"));
System.out.println(zdt);
Set<String> set = ZoneId.getAvailableZoneIds();
set.stream().forEach(System.out::println);
}
LocalDate
public static void localDateTest() {
//获取当前日期,只含年月日 固定格式 yyyy-MM-dd 2018-05-04
LocalDate today = LocalDate.now();
// 根据年月日取日期,5月就是5,
LocalDate oldDate = LocalDate.of(2018, 5, 1);
// 根据字符串取:默认格式yyyy-MM-dd,02不能写成2
LocalDate yesteday = LocalDate.parse("2018-05-03");
// 如果不是闰年 传入29号也会报错
LocalDate.parse("2018-02-29");
}
public static void localDateTransferTest(){
//2018-05-04
LocalDate today = LocalDate.now();
// 取本月第1天: 2018-05-01
LocalDate firstDayOfThisMonth = today.with(TemporalAdjusters.firstDayOfMonth());
// 取本月第2天:2018-05-02
LocalDate secondDayOfThisMonth = today.withDayOfMonth(2);
// 取本月最后一天,再也不用计算是28,29,30还是31: 2018-05-31
LocalDate lastDayOfThisMonth = today.with(TemporalAdjusters.lastDayOfMonth());
// 取下一天:2018-06-01
LocalDate firstDayOf2015 = lastDayOfThisMonth.plusDays(1);
// 取2018年10月第一个周三 so easy?: 2018-10-03
LocalDate thirdMondayOf2018 = LocalDate.parse("2018-10-01").with(TemporalAdjusters.firstInMonth(DayOfWeek.WEDNESDAY));
}
LocalTime
public static void localTimeTest(){
//16:25:46.448(纳秒值)
LocalTime todayTimeWithMillisTime = LocalTime.now();
//16:28:48 不带纳秒值
LocalTime todayTimeWithNoMillisTime = LocalTime.now().withNano(0);
LocalTime time1 = LocalTime.parse("23:59:59");
}
LocalDateTime
//转化为时间戳 毫秒值
long time1 = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
System.out.println(time1);
//时间戳转化为localdatetime
DateTimeFormatter df= DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss.SSS");
System.out.println(df.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time1),ZoneId.of("Asia/Shanghai"))));
CompletableFuture异步编程
https://cloud.tencent.com/developer/article/1366581
jdk1.8-ForkJoin框架剖析
https://www.jianshu.com/p/f777abb7b251