jdk1.8新特性知识点:
  • Lambda表达式
  • Stream API
  • 函数式接口
  • 方法引用和构造器调用
  • 接口中的默认方法和静态方法
  • 新时间日期API
  • default
 
Lambda表达式
    Lambda就是把我们之前一些复杂的代码更简单化,比如集合内容的判断比较/排序,我们之前可以进行遍历判断取出我们想要的数据或者写一个匿名内部类compareto等方法进行取出我们想要的数据,实际它们内部也就是进行了一些判断比较最终返回给了我们想要的结果。
    举例:场景一
        现在我们有三个用户 小明、小红、小强  他们的年龄分别是16, 18,20,现在我们要把这三个用户按年龄进行从小到大的排序。
        如果按原来的写法,我们首先想到的应该是 编写匿名内部类Comparator进行比较然后排序得到我们想要的结果吧,附图:
 
    举例:场景二 
        我们现在要对三个用户进行筛选,得到年龄是大于16岁的用户,我们首先想到的应该是进行遍历集合进行判断筛选,最后放入到一个新的集合吧,附图:

现在JDK1.8给我们提供了新的方式Lambda表达式,比上边的两个例子编写的代码更为简单更简介,下面我们来看一看怎么比上边的代码更简单。

    场景一:附图
    场景二:附图

 
下边是Lmabda表达式的语法总结:
 
口诀:左右遇一省括号,左侧推断类型省
 
注:当一个接口中存在多个抽象方法时,如果使用lambda表达式,并不能智能匹配对应的抽象方法,因此引入了函数式接口的概念。
 
先介绍一下Stream API,上边提到了Stream API,挨着写,下一个介绍函数式接口。
Stream API:
    Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简单来说,Stream API 提供了一种高效且易于使用的处理数据的方式。
     注意:1.Stream不会自己存储元素
               2.Stream不会改变源对象,相反他们会返回一个持有新结果集的Stream对象。
               3.Stream的操作是延迟执行的,这意味着他们会等到需要结果的时候才执行
               4.  只有当作终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值”、“延迟加载”  
               5. 每一个Stream流只能操作一次,如果第二次操作会报错stream has already been operated upon or closed
 
    Stream API的执行流程:
直接上代码:
    1.创建流Stream
    2.中间操作
    3.终止操作
 //3.终止操作
/**
* 查找和匹配
* allMatch-检查是否匹配所有元素
* anyMatch-检查是否至少匹配一个元素
* noneMatch-检查是否没有匹配所有元素
* findFirst-返回第一个元素
* findAny-返回当前流中的任意元素
* count-返回流中元素的总个数
* max-返回流中最大值
* min-返回流中最小值
*/
//3.1:allMatch检查是否匹配所有元素是否都成立,都成立返回true 否则返回false
Stream<Map<String, Object>> stream2 = maps.stream();
boolean a = stream2.allMatch(x -> Integer.valueOf(x.get("age").toString()) > 16);
System.err.println("结果:"+a); //false
//3.2:anyMatch检查是否至少匹配一个元素,只要有一个成立就返回true
Stream<Map<String, Object>> stream3 = maps.stream();
boolean b = stream3.anyMatch(x -> Integer.valueOf(x.get("age").toString()) > 16);
System.err.println("结果:"+b); //true
//3.3:noneMatch检查是否没有匹配所有元素,因为有成立的所以有匹配的元素,估 不成立
Stream<Map<String, Object>> stream4 = maps.stream();
boolean c = stream4.noneMatch(x -> Integer.valueOf(x.get("age").toString()) > 16);
System.err.println("结果:"+c); //false
//3.4:findFirst返回第一个元素,按照年龄从小到大排序返回第一个元素
Stream<Map<String, Object>> stream5 = maps.stream();
Map<String, Object> first = stream5.sorted((x,y) -> Integer.compare(Integer.valueOf(x.get("age")
.toString()),Integer.valueOf(y.get("age").toString()))).findFirst().get();
System.err.println(first.toString());//{sex=女, name=小红, age=16}
//3.5:findAny-返回当前流中的任意元素
Stream<Map<String, Object>> stream6 = maps.stream();
Map<String, Object> map = stream6.sorted((x,y) -> Integer.compare(Integer.valueOf(y.get("age")
.toString()),Integer.valueOf(x.get("age").toString()))).findAny().get();
//多次测试返回固定是这个,感觉因该是内部有一个算法排序然后返回其中固定某个 {sex=男, name=小明, age=18}
//排序之后返回的永远是第一个
System.err.println(map.toString());
//3.6:返回流中元素的总个数
Stream<Map<String, Object>> stream7 = maps.stream();
long count = stream7.count();
System.err.println("长度为:"+count); // 长度为:3
//TODO 最大最小就不测试了,自己可以试试

还有功能比较强大的两个终止操作 reduce和collect

reduce操作: reduce:(T identity,BinaryOperator)/reduce(BinaryOperator)-可以将流中元素反复结合起来,得到一个值
 /**
* reduce :规约操作
* 计算和
* 计算结果作为x,再从数组中取出新值作为y,进行下一步计算
* 结果在加上0 是最后的结果
*/
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer count2 = list.stream().reduce(0, (x, y) -> x + y);
System.out.println(count2); Stream<Map<String, Object>> stream8 = maps.stream();
//计算总年龄 也可以是浮点型数据 将Integer 换成Double就ok
Optional<Integer> op = stream8.map(m -> Integer.valueOf(String.valueOf(m.get("age"))))
.reduce(Integer::sum);
System.err.println(op.get()); //    
collect操作:Collect-将流转换为其他形式,接收一个Collection接口的实现,用于给Stream中元素做汇总的方法,转换为一个新的集合或者对象
 /**
* collect操作:Collect-将流转换为其他形式,
* 接收一个Collection接口的实现,用于给Stream中元素做汇总的方法
* Collectors.toList()/toSet()
*/
Set<Integer> ageList = list.stream().collect(Collectors.toSet());
ageList.stream().forEach(System.out::println);
//取名字,封装成hashset
HashSet<Integer> hs = list.stream()
.collect(Collectors.toCollection(HashSet::new));
System.err.println(hs.toString());

函数式接口:

        函数式接口的提出是为了给Lambda表达式的使用提供更好的支持。
什么是函数式接口?
        简单来说就是只定义了一个抽象方法的接口(Object类的public方法除外),就是函数式接口,并且还提供了注解:@FunctionalInterface
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口可以被隐式转换为 lambda 表达式。
Lambda 表达式和方法引用(实际上也可认为是Lambda表达式)上。
如定义了一个函数式接口如下:
 @FunctionalInterfaceinterface GreetingService
{
void sayMessage(String message);
} // 那么就可以使用Lambda表达式来表示该接口的一个实现(注:JAVA 8 之前一般是用匿名类实现的):
GreetingService greetService1 = message -> System.out.println("Hello " + message);
常见的四大函数式接口有:
        Consumer 《T》:消费型接口,有参无返回值
        Supplier 《T》:供给型接口,无参有返回值
        Function 《T,R》:函数式接口,有参有返回值
        Predicate《T》:断言型接口,有参有返回值,返回值是boolean类型
 /**
* @MethodName: functionInterface
* @Description: 四大函数式接口练习
* @param
* @return
* @author rongrong
* @date 2019-12-23
*/
public void functionInterface(){
/**
* 1.Consumer 《T》:消费型接口,有参无返回值
* 打印:
* 222222
* hello
*/
changeStr("hello",(str) -> System.err.println(str)); /**
* 2.Supplier 《T》:供给型接口,无参有返回值
* 打印:
* 111111
* str
*/
String value = getValue(() -> "str");
System.err.println(value); /**
* 3. Function 《T,R》::函数式接口,有参有返回值
* 打印:
* 333333
* 20000
*/
Long aLong = changeNum(100L, x -> x * 200);
System.err.println(aLong);
/**
* Predicate《T》: 断言型接口,有参有返回值,返回值是boolean类型
* 打印:
* true
*/
boolean rongrong = changeBoolean("rongrong", x -> x.equals("rongrong"));
System.err.println(rongrong); } /**
* Consumer<T> 消费型接口
* @param str
* @param con
*/
public void changeStr(String str, Consumer<String> con){
System.err.println("222222");
con.accept(str);
} /**
* Supplier<T> 供给型接口
* @param sup
* @return
*/
public String getValue(Supplier<String> sup){
System.err.println("111111");
return sup.get();
} /**
* Function<T,R> 函数式接口
* @param num
* @param fun
* @return
*/
public Long changeNum(Long num, Function<Long, Long> fun){
System.err.println("333333");
return fun.apply(num);
} /**
* Predicate<T> 断言型接口
* @param str
* @param pre
* @return
*/
public boolean changeBoolean(String str, Predicate<String> pre){
return pre.test(str);
}

在四大核心函数式接口基础上,还提供了诸如BiFunction、BinaryOperation、toIntFunction等扩展的函数式接口,都是在这四种函数式接口上扩展而来的,不做赘述。

总结:函数式接口的提出是为了让我们更加方便的使用lambda表达式,不需要自己再手动创建一个函数式接口,直接拿来用就好了,详细接口描述在下边。
 
 
方法引用:
        若lambda体中的内容有方法已经实现了,那么可以使用“方法引用”也可以理解为方法引用是lambda表达式的另外一种表现形式并且其语法比lambda表达式更加简单
(a) 方法引用
    三种表现形式:
        1. 对象:实例方法名
        2. 类::静态方法名
        3. 类::实例方法名 (lambda参数列表中第一个参数是实例方法的调用 者,第二个参数是实例方法的参数时可用)
 /**
*注意:
* 1.lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致!
* 2.若lambda参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method
* 下边写的例子 上边是不简化时的写法,下边的是对应的简化写法,就是方法引用
*/ //100
//
Consumer<Integer> con = (x) -> System.out.println(x);
con.accept(100);
// 方法引用-对象::实例方法
Consumer<Integer> con2 = System.out::println;
con2.accept(200); // 方法引用-类名::静态方法名
BiFunction<Integer, Integer, Integer> biFun = (x, y) -> Integer.compare(x, y);
Integer apply = biFun.apply(100, 200);
BiFunction<Integer, Integer, Integer> biFun2 = Integer::compare;
Integer result = biFun2.apply(100, 200);
//-1:-1
System.err.println(apply + ":" + result); // 方法引用-类名::实例方法名
BiFunction<String, String, Boolean> fun1 = (str1, str2) -> str1.equals(str2);
Boolean apply1 = fun1.apply("rong", "rong");
BiFunction<String, String, Boolean> fun2 = String::equals;
Boolean result2 = fun2.apply("hello", "world");
//true:false
System.out.println(apply1 + ":" + result2);
(b)构造器引用 
        格式:ClassName::new
 // 构造方法引用 类名::new
Supplier<String> sup = () -> new String();
System.out.println(sup.get());
Supplier<String> sup2 = String::new;
System.out.println(sup2.get()); // 构造方法引用 类名::new (带一个参数)
//x 代表是传进去的参数,也就是泛型中的Integer类型
//new String(...) 代表泛型中的String类型
Function<Integer, String> fun = x -> new String(String.valueOf(x));
System.err.println(fun.apply(100));
Function<String, String> fun3 = String::new;
System.out.println(fun3.apply("100"));
(c)数组引用
格式:Type[]::new
 // 数组引用
Function<Integer, String[]> arrayFun = (x) -> new String[x];
Function<Integer, String[]> arrayFun2 = String[]::new;
//给String数组设置了两个长度。但是值是null
String[] strArray = arrayFun2.apply(2);
Arrays.stream(strArray).forEach(System.out::println);
 
序号
接口 & 描述
1
BiConsumer<T,U>
代表了一个接受两个输入参数的操作,并且不返回任何结果
2
BiFunction<T,U,R>
代表了一个接受两个输入参数的方法,并且返回一个结果
3
BinaryOperator<T>
代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果
4
BiPredicate<T,U>
代表了一个两个参数的boolean值方法
5
BooleanSupplier
代表了boolean值结果的提供方
6
Consumer<T>
代表了接受一个输入参数并且无返回的操作
7
DoubleBinaryOperator
代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。
8
DoubleConsumer
代表一个接受double值参数的操作,并且不返回结果。
9
DoubleFunction<R>
代表接受一个double值参数的方法,并且返回结果
10
DoublePredicate
代表一个拥有double值参数的boolean值方法
11
DoubleSupplier
代表一个double值结构的提供方
12
DoubleToIntFunction
接受一个double类型输入,返回一个int类型结果。
13
DoubleToLongFunction
接受一个double类型输入,返回一个long类型结果
14
DoubleUnaryOperator
接受一个参数同为类型double,返回值类型也为double 。
15
Function<T,R>
接受一个输入参数,返回一个结果。
16
IntBinaryOperator
接受两个参数同为类型int,返回值类型也为int 。
17
IntConsumer
接受一个int类型的输入参数,无返回值 。
18
IntFunction<R>
接受一个int类型输入参数,返回一个结果 。
19
IntPredicate
:接受一个int输入参数,返回一个布尔值的结果。
20
IntSupplier
无参数,返回一个int类型结果。
21
IntToDoubleFunction
接受一个int类型输入,返回一个double类型结果 。
22
IntToLongFunction
接受一个int类型输入,返回一个long类型结果。
23
IntUnaryOperator
接受一个参数同为类型int,返回值类型也为int 。
24
LongBinaryOperator
接受两个参数同为类型long,返回值类型也为long。
25
LongConsumer
接受一个long类型的输入参数,无返回值。
26
LongFunction<R>
接受一个long类型输入参数,返回一个结果。
27
LongPredicate
R接受一个long输入参数,返回一个布尔值类型结果。
28
LongSupplier
无参数,返回一个结果long类型的值。
29
LongToDoubleFunction
接受一个long类型输入,返回一个double类型结果。
30
LongToIntFunction
接受一个long类型输入,返回一个int类型结果。
31
LongUnaryOperator
接受一个参数同为类型long,返回值类型也为long。
32
ObjDoubleConsumer<T>
接受一个object类型和一个double类型的输入参数,无返回值。
33
ObjIntConsumer<T>
接受一个object类型和一个int类型的输入参数,无返回值。
34
ObjLongConsumer<T>
接受一个object类型和一个long类型的输入参数,无返回值。
35
Predicate<T>
接受一个输入参数,返回一个布尔值结果。
36
Supplier<T>
无参数,返回一个结果。
37
ToDoubleBiFunction<T,U>
接受两个输入参数,返回一个double类型结果
38
ToDoubleFunction<T>
接受一个输入参数,返回一个double类型结果
39
ToIntBiFunction<T,U>
接受两个输入参数,返回一个int类型结果。
40
ToIntFunction<T>
接受一个输入参数,返回一个int类型结果。
41
ToLongBiFunction<T,U>
接受两个输入参数,返回一个long类型结果。
42
ToLongFunction<T>
接受一个输入参数,返回一个long类型结果。
43
UnaryOperator<T>
接受一个参数为类型T,返回值类型也为T。
 
 
 
 
 
 
 
 
 
 
 
 

JDK1.8新特性(一) ----Lambda表达式、Stream API、函数式接口、方法引用的更多相关文章

  1. jdk1.8新特性之lambda表达式

    lambda表达式其实就是指一个匿名函数,应用最广泛的就是匿名内部类的简化.在jdk1.8之前,我们定义一个匿名内部类可能需要写一大坨代码,现在有了lambda之后,可以写的很简洁了.但不是说lamb ...

  2. jdk1.8新特性之lambda表达式及在Android Studio中的使用举例

    Jdk1.8已经出很久了但是很多同学对它的特性在android studio 中的应用可能还不是很熟悉,今天我们就来对这个新特性在AS中做它的应用实践. 一.首先在有JDK1.8的情况下我们要在AS的 ...

  3. Java8 新特性学习 Lambda表达式 和 Stream 用法案例

    Java8 新特性学习 Lambda表达式 和 Stream 用法案例 学习参考文章: https://www.cnblogs.com/coprince/p/8692972.html 1.使用lamb ...

  4. java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合

    java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合 比如,我有一张表: entity Category.java service CategoryServic ...

  5. java8新特性之——lambda表达式的使用

    lambda表达式简介 个人理解,lambda表达式就是一种新的语法,没有什么新奇的,简化了开发者的编码,其实底层还是一些常规的代码.Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解 ...

  6. 【Java8新特性】Lambda表达式基础语法,都在这儿了!!

    写在前面 前面积极响应读者的需求,写了两篇Java新特性的文章.有小伙伴留言说:感觉Lambda表达式很强大啊!一行代码就能够搞定那么多功能!我想学习下Lambda表达式的语法,可以吗?我的回答是:没 ...

  7. 【Java8新特性】- Lambda表达式

    Java8新特性 - Lambda表达式 生命不息,写作不止 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! ...

  8. Java 8新特性-3 Lambda 表达式

    在 Java 8 之前,匿名内部类,监听器和事件处理器的使用都显得很冗长,代码可读性很差. 在Java 8 之前使用匿名内部类: 例如 interface ITestPrint{ public voi ...

  9. java8的新特性之lambda表达式和方法引用

    1.1. Lambda表达式 通过具体的实例去体会lambda表达式对于我们代码的简化,其实我们不去深究他的底层原理和背景,仅仅从用法上去理解,关注两方面: lambda表达式是Java8的一个语法糖 ...

随机推荐

  1. 目录:JAVA

    收藏: Java:类与继承

  2. SQL-W3School-函数:SQL 函数

    ylbtech-SQL-W3School-函数:SQL 函数 1.返回顶部 1. SQL 拥有很多可用于计数和计算的内建函数. 函数的语法 内建 SQL 函数的语法是: SELECT function ...

  3. python下multiprocessing和gevent的组合使用

    python下multiprocessing和gevent的组合使用 对于有些人来说Gevent和multiprocessing组合在一起使用算是个又高大上又奇葩的工作模式. Python的多线程受制 ...

  4. R-CNN论文学习

    Rich feature hierarchies for accurate object detection and semantic segmentation Tech report (v5) pr ...

  5. 001-poi-excel-基础、单元格使用操作

    一.概述 Apache POI是Apache软件基金会的开源项目,POI提供API给Java程序对Microsoft Office格式档案读和写的功能. .NET的开发人员则可以利用NPOI (POI ...

  6. 004-nginx简介、安装配置【源码安装和mac安装】、基本使用

    一.概述 1.1.Nginx是什么 Nginx是一款轻量级的Web服务器,也是一款轻量级的反向代理服务器[常用]. 1.2.Nginx能干什么 Nginx能干的事情很多,这里简要罗列一些: 1:直接支 ...

  7. hadoop目录命令

    下面是经常使用到的,以此记录备忘 1.查看hadoop目录 命令: hadoop fs -ls / 2.创建目录 命令:hadoop fs -mkdir /目录名 3.将文件上传hadoop中(也就是 ...

  8. PAT 甲级 1041 Be Unique (20 分)(简单,一遍过)

    1041 Be Unique (20 分)   Being unique is so important to people on Mars that even their lottery is de ...

  9. k8s常可能问的问题

    k8s常可能问的问题 1.为什么要用k8s 自我修复.pod水平自动伸缩.密钥和配置管理动态对应用进行扩容.缩容 服务发现.负载均衡 1.1.自我修复 比如误删pod后会自动创建,用 kind: Re ...

  10. AWS 云产品 CloudFront + ELB + EC2 + S3 构建虚拟主机动+静分离站点

    目录 一.架构图 二.实现步骤 2.1.EC2 配置 2.2.ELB 设置 2.2.1.创建目标组 2.2.2.创建负载均衡器 2.3.S3 设置 2.4.CloudFront 分配 2.4.1.创建 ...