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 类库的一部分,用来解决空指针异常。
接口定义
接口的作用:定义一套标准、规范,一个公共的规则,所以接口中的之声明方法签名,不提供方法体,具体实现由实现类完成。
接口中的属性:public static final,即只能是常量
接口中的方法:public abstract,即方法必须为抽象方法
接口没有构造方法,所以不能实例化
接口可以通过extends继承其他接口
接口的实现必须实现接口所有方法,否则该类应该抽象类
接口的作用
1)多继承,java对象只能有一个父类,通过接口可以实现多继承
2)有利于代码规范,定义接口,可以让不同的开发人员按照统一规范来完成项目的开发工作,防止开发人员随意命名,导致命名不清晰,代码混乱等
3)降低项目的耦合度,提高可扩展性。一个类被多个地方调用,当其中一个地方发生业务改变时,通过定义一个新的实现类来解决即可,而避免改变所有调用的地方。
接口的默认方法
接口中特殊的方法,被default修饰,可以包含方法体
public interface IHello {
void sayHi();
default void sayBye() { }
}
作用:扩展接口功能,不破坏现有代码,让接口扩展新的功能。默认方法跟接口中其他方法不同,它是可选的。子类可以根据需求选择是否需要重写该方法。
注意:若一个类实现了多个接口,那么多个接口中不应该包含相同的默认方法,编辑会报错,除非重写该默认方法。
接口中的静态方法
等同于类中的静态方法,调用时可不需要实现接口或实例化接口的实例,来完成方法的调用。
public interface IHello {
static void sayHello() {}
}
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注解:
该注解来定义接口,编译器强制检查接口中是否有且仅有一个抽象方法,如果不是,则编译出错
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;};
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;
注意:调用的为无参构造
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);
}
Stream:中文成为"流",一种对集合或者数组进行处理的工具,又被称为"操作符";操作符分类两类:中间操作符、终止操作符。一般来讲,流不会修改原来的数据,它会将操作后的数据保存到另一个对象中。
Stream使用步骤:
1)创建Stream对象
2)使用中间操作符进行操作
3)使用终止操作符
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();
对数据执行操作后,数据依然可以传递给下一级操作符。(一般都需要传递给终止操作符,因为中间操作符返回值为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
中间操作符处理数据后,须有终止操作符进行收集、消费操作。终止操作符只能用一次。
收集操作符:将数据收集起来 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)线程不安全 2)设计较差,java.util、java.sql都有日期类,而格式化类却在java.text包下,设计不合理 3)时区处理麻烦:日期类不提供国际化,没有时区支持 新版本:(java.time包) 1)Local(本地):简化了日期时间的处理,没有时区问题 2)Zoned(时区):通过制定时区处理日期时间问题
主要涉及的类为: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);