目录
java8新特性
个人的感受:虽然现在学习java8有点晚,但是现在还不去学,那不是更晚了?在这个it界,如果不去学习,那就只能被淘汰,学总比不学好,总之:不知道 < 知道(听说过) < 了解(会使用一点) < 正常使用(基本的使用没有问题) < 精通我们至少要能达到正常使用。虽然现在的一些项目可能还在用之前的jdk 版本,万一哪天要用了呢?多学习总是没错的
一、主要内容
- 1. Lambda 表达式
- 2. 函数式接口
- 3. 方法引用与构造器引用
- 4. Stream API
- 5. 接口中的默认方法与静态方法
- 6. 新时间日期 API
- 7. 其他新特性
二、java8新特性简介
- 速度更快
- 代码更少(增加了新的语法 Lambda 表达式)
- 强大的 Stream API
- 便于并行
- 最大化减少空指针异常 Optional
核心就是标红的 两个
三、具体介绍
3.1 Lambda表达式
为啥要使用这个?答:方便,快捷。
lambda 是一个匿名函数,我们可以把lambda表达式理解是一段可以传递的代码(将代码像数据一样的可以进行传递)。可以写出更简洁,更灵活的代码。作为一种更紧凑的代码风格,是java的语言表达能力得到了提升。
3.1.1简单的语法比较
既然是接口,那就从接口出发
public void test1(){
// 匿名内部类转换
// 匿名内部类
Runnable run = new Runnable() {
@Override
public void run() {
System.out.println("this is one ");
}
} ;
//lambda表达式 无参数 无返回值
Runnable runL = ()->{ System.out.println("this is one ");} ;
}
没有实际作用?看下面这个
public void test2(){
// 匿名内部类转换
TreeSet<Integer> treeSet = new TreeSet<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
});
// 简单应用
TreeSet<Integer> treeSet2 = new TreeSet<>(
(o1,o2)->Integer.compare(o1,o2)
);
}
3.2具体语法
敲黑板讲解:
Lambda 表达式在Java 语言中引入了一个新的语法元 素和操作符。这个操作符为 “->” , 该操作符被称 为 Lambda 操作符或剪头操作符。它将 Lambda 分为 两个部分:
- 左侧:指定了 Lambda 表达式需要的所有参数
- 右侧:指定了 Lambda 体,即 Lambda 表达式要执行 的功能。
3.2.1具体实现
语法格式一:无参,无返回值,Lambda 体只需一条
//lambda表达式 无参数 无返回值
Runnable runL = ()->{ System.out.println("this is one ");} ;
语句语法格式二:Lambda 一个参数语法
// 有一个参数 无返回值
Consumer<String> con = (args)-> System.out.println(args) ;
格式三:Lambda 只需要一个参数时,参数的小括号可以省略语法
// 有一个参数 无返回值
Consumer<String> con2 = args -> System.out.println(args) ;
格式四:Lambda 需要两个参数,并且有返回值
// 有两个参数 并且有返回值 ,
BinaryOperator<Long> fun = (x, y)->{ return x+y} ;
语法格式五:当Lambda 体只有一条语句时,return 与大括号可以省
// 有两个参数 并且有返回值 ,
BinaryOperator<Long> fun = (x, y)->{ x+y} ;
语法格式六:类型可以省略
// 简化一 有两个参数 并且有返回值 ,
BinaryOperator<Long> fun = ( Long x, Long y)->{ return x+y} ;
// 简化三 有两个参数 并且有返回值 ,如果lambda体中的数据只有一条语句,可以不用return ,也可以不用大括号
BinaryOperator<Long> fun3 = ( x, y)-> x+y ;
为啥类型可以省略:
Lambda 表达式中的参数类型都是由编译器推断 得出的。Lambda 表达式中无需指定类型,程序依然可 以编译,这是因为 javac 根据程序的上下文,在后台 推断出了参数的类型。Lambda 表达式的类型依赖于上 下文环境,是由编译器推断出来的。这就是所谓的 “类型推断”
lambda基础语法已经介绍完毕,下面介绍实际使用
使用之前我们需要知道一个知识点
3.3 什么是函数式接口
- 只包含一个抽象方法的接口,称为函数式接口。
- 你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)。
- 我们可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。
3.3.1 自定义函数式接口
/**
* @author yx start
* 1.只包含一个抽象方法的接口
* 2.@FunctionalInterface 注解,
* 这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包
* 含一条声明
* @create 2019/4/21,12:32
*/
@FunctionalInterface
public interface MyInterface<T> {
public T getValue(T t) ;
}
/**
* 进行调用
* @param args
*/
public static void main(String[] args) {
test4();
}
/**
* 将接口传递给自定义接口
* str -> str.toUpperCase() 就是对MyInterface 接口的实现。
*/
public static void test4(){
String strRes = testMyFun( str -> str.toUpperCase(), "abdced");
System.out.println(strRes);
}
/**
* 定义一个使用,传值自定义的接口(可以是)
* @param mf
* @param str
* @return
*/
private static String testMyFun(MyInterface<String> mf ,String str) {
return mf.getValue(str) ;
}
lambda 对接口实现,然后lambda体的实现可以自定义,不用像之前的那么写的死死的
3.3.2 内置四大核心函数式接口
我们不可能每次都是自己定义接口,太麻烦了。java有内置的。
* Consumer<T> 消费型接口 有参数 T,无返回 * Supplier<T> 供给型接口 无参数,有返回 T * Function<T, R>函数型接口有参数 T ,有返回 R * Predicate<T> 断定型接口 有参数T ,有返回Boolean
3.3.2.1 Consumer
Consumer<T> 消费型接口 有参数 T,无返回
@Test
public void TestconSumer(){
consumer(str->System.out.println(str.toLowerCase()),"MY_CONSOUMER ");
}
/**
* test 消费型接口
* @param con
* @param str
*/
public void consumer(Consumer<String> con, String str){
con.accept(str);
}
3.3.2.2 Supplier
Supplier<T>
Supplier<T> 供给型接口 无参数,有返回 T
需求:根据指定的数字,随机生成数据添加到集合中
// Supplier<T> 供给型接口 无参数,有返回 T
@Test
public void testSupp(){
List<Integer> list = getList(5, () -> (int) (Math.random() * 100));
list.forEach(System.out::println) ;
}
/***
*Supplier<T> 供给型接口 无参数,有返回 T
* 获取10个随机整数,添加到集合中
*
* @param num
* @param supplier
* @return
*/
public List<Integer> getList(int num, Supplier<Integer> supplier){
List list = new ArrayList( );
for (int i = 0; i < num; i++) {
System.out.println(supplier.get());
list.add( supplier.get());
}
return list ;
}
3.3.2.3 Function(使用比较多)
Function<T, R>函数型接口有参数 T ,有返回 R
简单的需求:针对参数字符串的变大写返回
//Function<T, R>函数型接口有参数 T ,有返回 R =====================
@Test
public void testFunction(){
String this_is_test_fun = getString(str -> str.toUpperCase(), "this is test Fun");
System.out.println( this_is_test_fun);
}
public String getString(Function<String,String> fun,String str ){
return fun.apply(str) ;
}
3.3.2.4 Predicate
Predicate<T> 断定型接口 有参数T ,有返回Boolean
需求:将list<String> str 中符合要求的过滤 要求:是否包含 "yx" 字符串
// Predicate<T> 断定型接口 有参数T ,有返回Boolean
@Test
public void testPre(){
List<String> stringres = new ArrayList<>();
List<String> strings = Arrays.asList("yxa,asd,yasdsad,yxja,sadasd".split(","));
for (int i = 0; i <strings.size() ; i++) {
String tempStr = strings.get(i) ;
if(filterYxStr(str->str.contains("yx"),tempStr)){
stringres.add(tempStr) ;
}
}
stringres.forEach(System.out::println);
}
public boolean filterYxStr(Predicate<String> predicate, String str){
return predicate.test(str);
}
以上都是简单的demo 演示、
还有其他的,这些核心的肯定有相应的子类可以做到
内置核心接口完。。
3.4 方法引用与构造器引用
干嘛的?这又是啥????
答: 别慌,方便我们稍微简单一点的。比如我们要做的lambda实现重,已经有方法已经实现了。我们就可以方法引用了。
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用
方法引用语法:使用操作符 “::” 将方法名和对象或类的名字分隔开来。
3.4.1 demo演示
使用场景:
- 对象 :: 实例方法
- 类 :: 静态方法
- 类 :: 实例方法
3.4.1.1 对象引用::实例方法
public void testRef(){
PrintStream print = System.out ;
// 之前的做法:
Consumer<String> sup = (str)-> print.println("lambda"+str) ;
// 方法引用,因为 PrintStream 有了 println 方法,所以就直接使用,括号都不用
Consumer<String> supRef = print::println;
}
3.4.1.2类:: 静态方法
// 类:: 静态方法 注意:参数要一致(lambda调用的方法体的返回值类型要和函数类别的返回值类型一致)
Comparator<Integer> com = (x,y)->Integer.compare(x,y) ;
Comparator<Integer> com2 = Integer::compare;
3.4.1.3 类::实例方法
// 类:: 实例方法 使用条件: 两个 参数,第一个参数是调用者,第二个是调用的参数时
BiPredicate<String,String> bp = (x,y)->x.equals(y);
BiPredicate<String,String> bp2 = String::equals;
3.4.2构造器引用
格式: ClassName::new
与函数式接口相结合,自动与函数式接口中方法兼容。 可以把构造器引用赋值给定义的方法,与构造器参数 列表要与接口中抽象方法的参数列表一致!
// 构造器引用
Supplier<Person> supplier = ()->new Person() ;
Supplier<Person> supplier2 = Person::new ;
// 如果多个构造器 调用的构造器根据参数的返回值决定
Function<String,Person> fun = str->new Person(str) ;
Function<String,Person> fun2 = Person::new;
Person person = fun2.apply("张飞");
public class Person{
private String name ;
private String address ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Person() {
}
public Person(String name, String address) {
this.name = name;
this.address = address;
}
public Person(String name) {
this.name = name;
}
}
强大的 Stream API 下篇接上 https://blog.csdn.net/yangxin_blog/article/details/89432653