JAVA8新特性 函数式接口 lambda表达式 StreamAPI 日期时间API

1.Java8新特性

1)默认方法:
    默认方法就是一个在接口里面有了一个实现的方法    
2)方法引用:
    方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。
    与lambda联合使用,可以使语言的构造更紧凑简洁,减少冗余代码。
3)Lambda表达式:
    Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中。
4)Stream API:
    新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
5)Date Time API:
    加强对日期与时间的处理
6)Optional类:
    Optional类已经成为Java 8 类库的一部分,用来解决空指针异常。

1.1 关于接口

1.1.1 原始接口

接口定义

接口的作用:定义一套标准、规范,一个公共的规则,所以接口中的之声明方法签名,不提供方法体,具体实现由实现类完成。

接口中的属性:public static final,即只能是常量

接口中的方法:public abstract,即方法必须为抽象方法

接口没有构造方法,所以不能实例化

接口可以通过extends继承其他接口

接口的实现必须实现接口所有方法,否则该类应该抽象类

 

接口的作用

1)多继承,java对象只能有一个父类,通过接口可以实现多继承

2)有利于代码规范,定义接口,可以让不同的开发人员按照统一规范来完成项目的开发工作,防止开发人员随意命名,导致命名不清晰,代码混乱等

3)降低项目的耦合度,提高可扩展性。一个类被多个地方调用,当其中一个地方发生业务改变时,通过定义一个新的实现类来解决即可,而避免改变所有调用的地方。

1.1.2 接口新特性(1.8)

接口的默认方法

接口中特殊的方法,被default修饰,可以包含方法体

  public interface IHello {
    void sayHi();
    default void sayBye() { }
  }

作用:扩展接口功能,不破坏现有代码,让接口扩展新的功能。默认方法跟接口中其他方法不同,它是可选的。子类可以根据需求选择是否需要重写该方法。

注意:若一个类实现了多个接口,那么多个接口中不应该包含相同的默认方法,编辑会报错,除非重写该默认方法。

接口中的静态方法

等同于类中的静态方法,调用时可不需要实现接口或实例化接口的实例,来完成方法的调用。

  public interface IHello {
    static void sayHello() {}
  }

1.2 Lambda表达式

1.2.1 函数式接口

a.函数式接口

有且仅包含一个抽象方法的接口(可以包含一个或多个静态或默认方法)。

1.8之前: 
   java.lang.Runnable java.util.concurrent.Callable java.util.Comparator java.io.FileFilter 
1.8之后: 
   java.util.function、Predicate 、Supplier

b.使用场景

Lambda表达式,使用Lambda表达式可以简化匿名内部类的实现

@FunctionalInterface注解:
    该注解来定义接口,编译器强制检查接口中是否有且仅有一个抽象方法,如果不是,则编译出错

1.2.2 Lambda表达式

Lambda 允许把函数作为一个方法的参数或返回值(函数作为参数传递进方法中),使用 Lambda 表达式可以使代码变的更加简洁紧凑。

语法: 
   (parameters) -> expression 或 (parameters) ->{ statements; } 
简化版:
   ()-> {} ()代表参数,{}代表方法体,->代表运算符 
注意: 
   1) 所有参数类型,均可以省略
   2) 当参数只有一个,小括号可以省略 
   3) 无返回值情况,当方法体只有一条语句,可以省略大括号 
   4) 有返回值情况,当方法体只有一条语句,可以省略大括号和return

示例:

1)无参无返回

public interface IHello {
    void sayHello();
}
IHello iHello = () -> {System.out.println("");};

2)单参,无返回 

public interface IHello2 {
     void sayBye(String a);
}
IHello2 iHello2 = (a) ->{System.out.println("a:" + a);};

 3)多参,无返回

public interface IHello3 {
    void sayHi(int a,int b);
}
IHello3 iHello3 = (a,b)->{ System.out.println(a + b);};

4)无参数,有返回 

public interface IHello4 {
    int sayHi();
}
IHello4 iHello4 = () -> {return 1;};

5)单参数,有返回 

public interface IHello5 {
    int sayHi(int a);
}
IHello5 iHello5 = (a) ->{return a*10;};

6)多参数,有返回值 

public interface IHello6 {
    int sayHi(int a,int b);
}
IHello6 iHello6 = (a,b) -> {return a+ b;};

1.2.3 Lambda表达式的特殊使用

a.方法引用

Lambda表达式可以直接指向一个已经实现的方法

要求:①:该方法的参数数量和参数类型必须跟接口中的方法一致 ②:该方法的返回值类型必须与接口中的一致

public interface IHello5 {
    int sayHi(int a);
}
public static int change(int a) {
    return a;
}
IHello5 iHello5 = a -> change(a);

b.双冒号(::)的使用

普通方法:(参数是某个对象,调用该对象的方法)
public interface IPerson {
    int getPerson(Person person);
}
原装版:IPerson iPerson = (person) -> {return person.getAge();};
简化版:IPerson iPerson = Person::getAge;
​注意:参数对象调用的方法必需是无参
构造方法:(返回值是某个对象)
public interface IPerson {
    Person getPerson();
}
原装版:IPerson iPerson = () -> {return new Person();};
简化版:IPerson iPerson = Person::new;
​
注意:调用的为无参构造

1.2.4 系统内置函数式接口

Consume:参数为T,无返回
public interface Consumer {
    void accept(T t);
}
​
Supplier:无参有返回
public interface Supplier {
    T get();
}
​
Predicate:泛型参数T,返回值boolean
public interface Predicate {
    boolean test(T t);
}
​
Function:参数为T,返回值为R
public interface Function {
    R apply(T t);
}

1.3 StreamAPI

1.3.1 什么是Stream

Stream:中文成为"流",一种对集合或者数组进行处理的工具,又被称为"操作符";操作符分类两类:中间操作符、终止操作符。一般来讲,流不会修改原来的数据,它会将操作后的数据保存到另一个对象中。

Stream使用步骤:

1)创建Stream对象

2)使用中间操作符进行操作

3)使用终止操作符

1.3.2 创建stream对象

stream对象的获取,可以分为数组、list、set、map(可以得到key的set集合、value的list集合)

数组

String[] strArray = new String[] {"apple", "banana", "orange", "waltermaleon", "grape"};
​
Stream.of(strArray)//第一种
Arrays.stream(strArray)//第二种

list、set

List stuList = new ArrayList();
stuList.stream();//串行
stuList.parallelStream();//并行
​
Set set = new HashSet<>();
set.stream();
set.parallelStream();

1.3.2 中间操作符

对数据执行操作后,数据依然可以传递给下一级操作符。(一般都需要传递给终止操作符,因为中间操作符返回值为Stream对象,不传递给终止操作符返回处理后的数据没有意义)

中间操作符主要分为8种:

转换操作符:
    把原始数据转换为你所需要的数据,默认可转换成int、long、double类型 map,mapToInt,mapToLong,mapToDouble 
拍平操作符:
    即拆开,把数组拆分成单个字段,默认提供了拍平成int,long,double的操作符.
    flatmap,flatmapToInt,flatmapToLong,flatmapToDouble                                              
限流操作符:
    比如数据流中有10条数据,只取其中三条 limit 
去重操作符:
    去掉重复数据 distinct 
过滤操作符:
    筛掉不想要的数据 filter 
跳过操作符:
    跳过某些元素 skip 
挑出操作符:
    对数据进行某些操作,如读取、编辑修改等 peek 
排序操作符: 
    sorted 

map转换操作符

String[] strArray = new String[] {"apple", "banana", "orange", "waltermaleon", "grape"};
Stream.of(strArray)
    .map(e -> e.length())
    .forEach(e -> System.out.println(e));

flatMap拍平操作符

 Stream.of("a-b-c-d","e-f-i-g-h")
     .flatMap(e->Stream.of(e.split("-")))
     .forEach(e->System.out.println(e));

limit限流操作符

Stream.of(1,2,3,4,5,6)
    .limit(3) //限制三个
    .forEach(e->System.out.println(e));

distinct去重操作符

Stream.of(1,2,3,1,2,5,6,7,8,0,0,1,2,3,1)
    .distinct() //去重
    .forEach(e->System.out.println(e));

filter过滤操作符

 Stream.of(1,2,3,1,2,5,6,7,8,0,0,1,2,3,1)
     .filter(e->e>=5) //过滤小于5的
     .forEach(e->System.out.println(e));

skip跳过操作符

Stream.of(1,2,3,4,5,6,7,8,9)
    .skip(4) //跳过前四个
    .forEach(e->System.out.println(e)); 

peek挑出操作符

User w = new User("w",10);
User x = new User("x",11);
User y = new User("y",12);
Stream.of(w,x,y)
    .peek(e->{e.setName(e.getAge()+e.getName());}) //重新设置名字 变成 年龄+名字
    .forEach(e->System.out.println(e.toString()));

sorted排序操作符

Stream.of(2,1,3,6,4,9,6,8,0) 
    .sorted()  //默认排序
    .forEach(e->System.out.println(e));
​
User x = new User("x",11);
User y = new User("y",12);
User w = new User("w",10);
Stream.of(w,x,y)
    .sorted((e1,e2)->e1.age>e2.age?1:e1.age==e2.age?0:-1)
    .forEach(e->System.out.println(e.toString()));
    
注意:多重三元运算符(三目运算符)嵌套
String str =  a.equals("123") ? "123" : ( b.equals("456") ? "456" : "789");
//如果a等于123,就给str赋值123;否则,如果b等于456,就给str赋值123,前面两个如果都不成立就赋值789

 

1.3.3 终止操作符

中间操作符处理数据后,须有终止操作符进行收集、消费操作。终止操作符只能用一次。

收集操作符:将数据收集起来
    collect
统计操作符:
    count
查找操作符:
    findFirst,findAny
匹配操作符:流中是否存在符合条件的元素,返回boolean值
    noneMatch、allMatch、anyMatch
最值操作符:
    max,min
遍历操作符:
    forEach
数组操作符:将数据流元素变为数组
    toArray
规约操作符:将整个数据流规约为一个值,count/min/max都属于规约
    reduce

collect收集操作符

Set stringSet = 
    Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
    .collect(Collectors.toSet()) //set 容器

count统计操作符

long count = 
    Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
    .count();

查找操作符

findFirst:取流中的第一个元素
    Optional stringOptional = 
        Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
        .findFirst();
    stringOptional.get();//得到第一个元素
​
​
findAny:获取流中任意一个元素
    Optional findFirst = 
        Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
        .findAny();
     stringOptional.get();//得到任意一个元素,实际还是第一个

匹配操作符

boolean result = Stream.of("aa","bb","cc","aa")
                .noneMatch(e->e.equals("aa"));
noneMatch:没有一个匹配返回true
allMatch:全部匹配返回true
anyMatch:任意一个匹配返回true

最值操作符:

Optional integerOptional = 
    Stream.of(0,9,8,4,5,6,-1)
    .max((e1,e2)->e1.compareTo(e2));//max元素中最大的
    .min((e1,e2)->e1.compareTo(e2));//min元素中最大的

reduce规约操作符

所有的元素归约成一个,比如对所有元素求和,乘等
int sum = Stream.of(0,9,8,4,5,6,-1)
    .reduce(0,(e1,e2)->e1+e2);

toArray 数组操作符

转成数组
Object[] objects=Stream.of(0,2,6,5,4,9,8,-1)
                .toArray();

 

1.4 日期时间API

1.4.1 新旧版本的区别

旧版本:
    1)线程不安全
    2)设计较差,java.util、java.sql都有日期类,而格式化类却在java.text包下,设计不合理
    3)时区处理麻烦:日期类不提供国际化,没有时区支持
新版本:(java.time包)
    1)Local(本地):简化了日期时间的处理,没有时区问题
    2)Zoned(时区):通过制定时区处理日期时间问题  

1.4.2 本地化日期时间API

主要涉及的类为:LocalDate、LocalTime、LocalDateTime

方法 描述
now() 静态方法,根据当前时间创建对象
of() 静态方法,根据指定日期/时间创建 对象
plusDays, plusWeeks, plusMonths, plusYears 向当前 LocalDate 对象添加几天、 几周、几个月、几年
minusDays, minusWeeks, minusMonths, minusYears 从当前 LocalDate 对象减去几天、 几周、几个月、几年
plus, minus 添加或减少一个 Duration或 Period
withDayOfMonth, withDayOfYear, withMonth, withYear 将月份天数、年份天数、月份、年 份修改为指定的值并返回新的 LocalDate对象
getDayOfMonth 获得月份天数(1-31)
getDayOfYear 获得年份天数(1-366)
getDayOfWeek 获得星期几(返回一个 DayOfWeek 枚举值)
getMonth 获得月份, 返回一个 Month枚举值
getMonthValue 获得月份(1-12)
getYear 获得年份
until 获得两个日期之间的 Period 对象, 或者指定 ChronoUnits的数字
isBefore, isAfter 比较两个 LocalDate
isLeapYear 判断是否是闰年

 

******对象创建******
LocalDate localDate = LocalDate.now();//获取当前日期
LocalDate localDate = LocalDate.of(year, month, dayOfMonth);//获取特定日期
​
******获取年、月、日信息******
int year = localDate.getYear();//年
int monthValue = localDate.getMonthValue();//月
int dayOfMonth = localDate.getDayOfMonth();//日
int dayOfYear  = localDate.getDayOfYear();//一年中的第几天
int dayOfWeek = localDate.getDayOfWeek();//周几
​
******枚举对象ChronoField获取年、月、日信息******
int year = localDate.get(ChronoField.YEAR);
int month = localDate.get(ChronoField.MONTH_OF_YEAR);
int day = localDate.get(ChronoField.DAY_OF_MONTH);
​
******日期修改******
LocalDate date = localDate.withYear(year);//变为指定年
LocalDate date = localDate.withMonth(month);//变为指定月
LocalDate date = localDate.withDayOfMonth(dayOfMonth);//变为指定日
//日期添加
LocalDate date = localDate.plus(amountToAdd, unit);
LocalDate date = localDate.plusYears(yearsToAdd);
LocalDate date = localDate.plusMonths(monthsToAdd);
LocalDate date = localDate.plusWeeks(weeksToAdd);
LocalDate date = localDate.plusDays(daysToAdd)
//日期减少
LocalDate date = localDate.minnus(amountToAdd, unit);
LocalDate date = localDate.minnusYears(yearsToAdd);
LocalDate date = localDate.minnusMonths(monthsToAdd);
LocalDate date = localDate.minnusWeeks(weeksToAdd);
LocalDate date = localDate.minnusDays(daysToAdd)
​
******日期比较******
localDate.isAfter(otherDate)
localDate.isBefore(otherDate)
​
******其他方法******
int len = localDate.lengthOfMonth();//31(这个月有多少天)
boolean leap = localDate.isLeapYear();//false(是不是闰年)
localDate.toEpochDay() - specialDay.toEpochDay();//日期间隔天数

DateTimeFormatter

//解析日期
String dateStr= "2018年12月18日";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
LocalDate date= LocalDate.parse(dateStr, formatter);
​
//日期转换为字符串
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy年MM月dd日 hh:mm a");
String nowStr = now .format(format);
System.out.println(nowStr);

 

你可能感兴趣的:(原创,JAVA,java,lambda,stream,编程语言,经验分享)