JDK1.8新特性

   1、接口:默认方法、 静态方法
   2、Lambda表达式和StreamAPI
   3、Optional类
   4、新的日期时间API
  
  Lambda表达式:为了简化代码,使得Java支持
   StreamAPI:为了支持内存中的数据的筛选、管理等
   Optional类:为了避免,简化空指针的处理
  新的日期时间API:为了解决原来老版的日期时间(1)对象的可变性(2)闰秒的考虑(3)本地化考虑
  

一、Lambda表达式


* Lambda表达式是实现SAM接口的语法糖,使得Java支持函数式编程。
*
* 原来Java要给Runnable类型的形参,一个对象:
* Thread(Runnable target),给target赋值一个对象,一个匿名内部类的对象
* new Runnable(){ @Override
public void run() {
System.out.println("hello");
} }
*
* 现在使用Lambda表达式:
* Thread(Runnable target),给target赋值的是一段代码:
* () -> System.out.println("hello")
*
* 左边():其实是方法的形参列表
* 右边:System.out.println("hello")是方法体
*
* () -> System.out.println("hello")相当于是一个函数。
*
*
* SAM接口:函数式接口,Single Abstract Method,这个接口只有一个唯一的抽象方法。
* 例如:Runnable接口是一个函数式接口,它只有一个抽象方法:public void run();
*
* 换句话说:目前Java的Lambda表达式,只适合给SAM接口赋值。
* Lambda表达式是给SAM接口赋值的,因此SAM接口的抽象方法的方法签名就很重要了。
* 重点关注抽象方法的:形参列表,返回值类型
*
* Lambda表达式的语法:
* (形参列表) -> {Lambda体} * 说明:
* (1)Lambda表达式的(形参列表)就是你给赋值的SAM接口的抽象方法的形参列表
* (2)->是称为Lambda操作符,中间不要加空格
* (3){Lambda体}就是你给赋值的SAM接口的抽象方法的方法体 * 方法的形式:
* 1、无参无返回值
* 2、有参无返回值
* 3、无参有返回值
* 4、有参有返回值
*
* 提示:
* (1)如果我们的(形参列表),只有一个形参,并且类型是已知的或可以推断的,那么可以省略(形参的类型),只要写形参名
* (2)如果{Lambda体}只有一个语句,那么可以省略{}和这句语句的;,并且如果这一句是return语句,这个return也可以省略
* (3)如果我们的(形参列表),无参的,或者是参数有多个的,那么()绝对不能省略
* (4)如果抽象方法有返回值,并且{}没有省略的话,那么return也不能省略
*/
函数式接口:SAM接口
* Single Abstract Method,即该接口中只有一个抽象方法需要实现,当然该接口可以包含其他非抽象方法。
*
* 原来JDK1.8之前就已经存在以下接口,符号这样的特征:
* (1)java.lang.Runnable:public void run();
* (2)java.lang.Comparable<T>:int compareTo(T t)
* (3)java.util.Comparator<T>:int compare(T t1, T t2)
* (4)java.io.FileFilter:public boolean accept(File pathname)
* (5)java.lang.reflect.InvocationHandler:public Object invoke(Object proxy, Method method, Object[] args)
* (6)java.lang.Iterable<T>: Iterator iterator()
* ....
*
* 函数式接口最好用一个注解标记一下:@FunctionalInterface
*
* JDK1.8之前的那些满足SAM特征的接口是否都加了呢?
* (1)java.lang.Runnable
* (3)java.util.Comparator<T>
* (4)java.io.FileFilter
* 如果没加@FunctionalInterface,表示将来可能扩展其他的抽象方法,变成非SAM接口。
* 结论:最好只对加了@FunctionalInterface的接口使用Lambda表达式。
*
* JDK1.8之后又增加了很多新的函数式接口。

JDK1.8增加的函数式接口:java.util.function

* 它设计的这些个接口,基本能保证大多数接口的需求,不需要重新设计新的接口。
* 分为四大类:
* 1、消费型接口:它的抽象方法的特征 有参无返回值
* 2、供给型接口:它的抽象方法的特征 无参有返回值
* 3、判断型接口:它的抽象方法的特征 有参有返回值,并且返回值类型是boolean
* 4、功能型接口:它的抽象方法的特征 有参有返回值
*
* 一、消费型接口:有参无返回值
* 1、Consumer<T> void accept(T t)
* 2、BiConsumer<T,U> void accept(T t,U u)
* 3、DoubleConsumer void accept(double value)
* 4、IntConsumer void accept(int value)
* 5、LongConsumer void accept(long value)
* 6、ObjDoubleConsumer<T> void accept(T t, double value)
* 6、ObjIntConsumer<T> void accept(T t, int value)
* 6、ObjLongConsumer<T> void accept(T t, long value) * 二、供给型接口:无参有返回值
* 1、Supplier<T> T get()
* 2、BooleanSupplier boolean getAsBoolean()
* 3、DoubleSupplier double getAsDouble()
* 4、IntSupplier int getAsInt()
* 5、LongSupplier long getAsLong() * 三、判断型接口:有参,但是返回值类型是boolean结果
* 1、Predicate<T> boolean test(T t)
* 2、BiPredicate<T,U> boolean test(T t,U u)
* 3、DoublePredicate boolean(double value)
* 4、IntPredicate boolean(int value)
* 5、LongPredicate boolean(long value) * 四、功能型接口:有参有返回值
* 1、Function<T,R> R apply(T t)
* 2、UnaryOperator<T> T apply(T t) 与上一个的区别就是形参的类型与返回值的类型是一样 * 3、DoubleFunction<R> R apply(double value)
* 4、IntFunction<R> R apply(int value)
* 5、LongFunction<R> R apply(long value) * 6、ToDoubleFunction<T> double apply(T t)
* 7、ToIntFunction<T> int apply(T t)
* 8、ToLongFunction<T> long apply(T t) * 9、DoubleToIntFunction int int applyAsInt(double value)
* 10、DoubleToLongFunction......
* 11、IntToDoubleFunction......
* 12、IntToLongFunction......
* 13、LongToDoubleFunction......
* 14、LongToIntFunction ......
*
* 15、DoubleUnaryOperator double applyAsDouble(double value)
* 16、IntUnaryOperator...
* 17、LongUnaryOperator...
*
* 19、BiFunction<T,U,R> R apply(T t, U u)
* 20、BinaryOperator<T> T apply(T t1, T t2)
* 21、ToDoubleBiFunction<T,U> double apply(T t, U u)
* .... * 方法引用和构造引用:
* 当Lambda表达式出现更特殊的情况时,我们可以对Lambda表达式进行再次简化。
* (1)当{Lambda体}的实现是通过调用一个类或一个对象的现有的方法来完成功能时。
* (2)你这个Lambda表达式所赋值的SAM接口的抽象方法的形参列表与返回值类型与实现{Lambda体}所调用的方法的形参列表与返回值类型对应。
*
* 方法引用的语法:
* (1)对象名::实例方法名
* (2)类名::静态方法名
* (3)类名::实例方法名
* 构造引用:
* (4)构造器名::new
* (5)数组类型::new
*/

Optional类

* 设计Optional类的初衷:因为Java的对象可能为null值,当用null值去调用方法,属性等时,会报NullPointerExecption空指针异常。
* 程序中为了避免这个空指针异常,会需要加入大量的非空判断,这样会导致程序中有很多重复的非空判断。
*
* Optional是一个容器。
* 数组和集合是用来装一堆(大量)对象的容器,而Optional是用来包装一个对象的容器。
*
* java.util.Optional<T>,这个T就是所包装的对象的类型。
* 1、如何包装对象?
* (1)static <T> Optional<T> empty() :包装一个空对象
* (2)static <T> Optional<T> of(T value) :只能用来包装“非空”对象
* (3)static <T> Optional<T> ofNullable(T value) :包装一个对象,这个对象可以是null,也可以非空
*
* 2、如何拿出这个被包装的对象
* (1)T get()
* 可以取出Optional容器中的对象,但是如果容器中的对象是null,那么会报java.util.NoSuchElementException: No value present
* (2)T orElse(T other)
* 如果Optional容器中的对象是非空,就返回该对象,如果是空的,就用other来代替。
* (3)T orElseGet(Supplier<? extends T> other)
* 如果Optional容器中的对象是非空,就返回该对象,如果是空的,就用由Supplier这个供给型接口提供的对象来代替
* (4) T orElseThrow(Supplier<X> exceptionSupplier)
* 如果Optional容器中的对象是非空,就返回该对象,如果是空的,就抛出你指定的异常对象
*
* 3、对所包装的对象,进行判断或处理
* (1)Optional<T> filter(Predicate<? super T> predicate) :
* 如果Optional容器中的对象满足你指定的条件,就保留,否则就清空。
* (2)<U> Optional<U> map(Function<? super T,? extends U> mapper)
* 如果Optional容器中的对象非空,可以对该对象进行处理,如何处理,由Function接口的lambda体来决定。

StreamAPI

* 原来的数据都在数据库中,现在很多数据都在内存中,例如:在集合、数组等容器中。
* 我们要对内存中的数据进行筛选、查找等各种操作,那么我们就可以使用StreamAPI,
* 像我们用SQL语句对象数据库一样操作。
*
* Stream是一个数据的渠道,专门对数据进行加工处理的渠道,不是数据本身。
* Stream的特点:
* (1)不负责存储数据,存储数据仍然是集合、数组等容器。
* (2)Stream对数据的加工,不会影响数据源(集合、数组等容器中的数据),而是产生一个新的副本。
* 每一次对Stream的操作都会产生一个新的Stream对象。
* (3)Stream的加工操作是一个延迟操作,只有在最后拿结果时,才一口气执行完,
* 创建Stream->(1)加工1(2)加工2....->取结果
*
Stream的操作分为三步:
  (1)创建一个Stream
  (2)中间操作:可以很多步
   (3)终结操作:拿结果
   一旦结束,这个Stream结束了,如果要重新加工,要重新创建。
一、如何创建Stream
* 1、通过集合来创建Stream
* Collection系列的集合.stream()
*
* 2、通过数组来创建Stream
* Arrays.stream(数组)
*
* 3、Stream.of(...)
*
* 4、无限流
*
* static <T> Stream<T> generate(Supplier<T> s)
* static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
*/
    @Test
public void test1(){
ArrayList<String> list = new ArrayList<>();
list.add("Hello");
list.add("world"); String[] arr = {"hello","java","world"}; Stream<String> stream = list.stream();
Stream<String> stream2 = Arrays.stream(arr); Stream.of("Hi","kk");
} @Test
public void test2(){
Stream<Integer> ite = Stream.iterate(1, t -> t + 2); //T seed :UnaryOperator<T> 是一个SAM接口,是一个功能型接口
//抽象方法:T apply(T t)
ite.forEach((t) -> System.out.println(t));
//ite.forEach(System.out::println); }

中间操作----每次中间操作都会返回一个新的stream,要重新接收

  @Test
public void test1(){
//(1)filter(Predicate p):按照p指定的条件进行过滤
Stream<Integer> stre = Stream.of(1, 2, 3, 4, 5, 6);
Stream<Integer> fil = stre.filter((t) -> t%2 == 0);
fil.forEach(System.out::println); //(2)distinct():去重
Stream.of(1,3,6,2,6,6,8,9)
.distinct() //去除重复的元素
.forEach(System.out::println); //(3)limit(long maxSize):取出前maxSize个
Stream.of(1,3,6,2,6,6,8,9)
.limit(3) //取前3个
.forEach(System.out::println); //(4)skip(long n):跳过前n个
Stream.of(1,3,6,2,6,6,8,9)
.skip(4) //把前4个跳过去
.forEach(System.out::println); //(5)peek(Consumer action)
long count = Stream.of(1,3,6,2,6,6,8,9)
.peek((t) -> System.out.println(t))
//.forEach(System.out::println); //不加.count输出是每个元素都重复了2遍;
.count();
System.out.println("count=" + count); //8 //(6)sorted() 要求元素实现java.lang.Comparable
Stream.of(7,3,6,2,4,6,8,9) //创建Stream
.sorted() //从小到大排序
.forEach(t -> System.out.println(t)); //终结操作 //(7)sorted(Comparator com)可以指定定制比较器
ArrayList<Employee> list = new ArrayList<>();
list.add(new Employee(2, "张三", 100000));
list.add(new Employee(1, "李四", 8000));
list.add(new Employee(3, "王五", 9000));
//list.stream().sorted((t1, t2) -> Double.compare(t1.getSalary(), t2.getSalary()));
list.stream().sorted((t1, t2) -> Double.compare(t1.getSalary(), t2.getSalary()))
.forEach(System.out::println); //(8)map(Function f):给stream中的每一个数据进行xx操作,结果仍然放回stream中,最终生成一个新的流
list.stream() //设置值!!!!
.map(t -> {t.setSalary(t.getSalary() + 100); return t;}) //中间操作 Function<T,R>: R apply(T t)
.forEach(System.out::println); //(9)mapToDouble(ToDoubleFunction f)
OptionalDouble reduce = list.stream()
.mapToDouble((t) -> t.getSalary())
.reduce((t1, t2) -> t1 + t2);
System.out.println(reduce.getAsDouble()); //117300.0 /*(10)flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
* Function<T,R>的抽象方法 R apply(T t),这的R是一个Stream
* 对stream中的每一个数据进行某个操作,会得到一个stream,然后把这些个stream再合成一个大的stream
*/
Stream.of("hello","java","wolrd")
.flatMap(t -> Stream.of(t.split("|")))
.forEach(System.out::println); }

Stream终结操作

* Stream:
* (1)创建:必须有
* (2)中间操作:0~n步
* (3)终结操作:必须有
*
* 三、Stream的终结操作
* 1、void forEach(Consumer c):遍历stream中的数据
* 2、long count():统计流中的数据的个数
* 3、boolean allMatch(Predicate p):判断流中的数据是否都满足p的条件
* boolean anyMatch(Predicate p):判断流中的数据是否至少有一个满足p的条件
* boolean noneMatch(Predicate  p):判断流中的数据是否都不满足p的条件
* 4、Optional<T> findFirst() :返回流中的第一个
* Optional<T> findAny() :返回流中的任意一个,如果流是固定的,那么相当于findFirst()
*
* 5、Optional<T> max(Comparator c)
* Optional<T> min(Comparator c)
*
* 6、U reduce(BinaryOperator b) :把流中的数据,返回结合,得到一个值
* 7、R collect(Collector c):把流中的数据收集起来放到一个容器中
*
* 工具类:Collectors
*
*
* 区别:
* Collection和Collector
* Collections(Collection集合的工具类)和Collectors
  @Test
public void test1(){
Random random = new Random();
long count = Stream.generate(() -> random.nextInt(100))
.limit(10)
.peek(System.out::println)
.filter(t -> t%2 == 0)
.count();
System.out.println("偶数的个数:" + count);
} @Test
public void test2(){
boolean flag = Stream.of(1, 2, 3, 4)
.allMatch(num -> num < 4);
System.out.println(flag); //false
} @Test
public void test3(){
ArrayList<Employee> list = new ArrayList<>();
list.add(new Employee(2, "张三", 100000));
list.add(new Employee(1, "李四", 8000));
list.add(new Employee(3, "王五", 9000));
Optional<Employee> max = list.stream()
.max((t1, t2) -> Double.compare(t1.getSalary(), t2.getSalary()));
System.out.println(max.get().getSalary()); Optional<Integer> sum = Stream.of(1,2,3,4)
.reduce((t1, t2) -> t1+t2);
System.out.println(sum);
} @Test
public void test4(){
ArrayList<Employee> list = new ArrayList<>();
list.add(new Employee(2, "张三", 100000));
list.add(new Employee(1, "李四", 8000));
list.add(new Employee(3, "王五", 9000));
list.add(new Employee(4, "小路", 7000));
list.add(new Employee(5, "小周", 8800)); //找出所有薪资低于10000的员工,放到一个集合中
List<Employee> collect = list.stream()
.filter(emp -> emp.getSalary() < 10000)
.collect(Collectors.toList());
for (Employee employee : collect) {
System.out.println(employee);
}
}

JavaSE | Lambda| Optional| Stream API的更多相关文章

  1. Java8中的 lambda 和Stream API

    前言 ​ 由于项目中用到了比较多有关于 Java8 中新的东西,一开始自己只是会写,但是写起来不太顺,然后就在网上找到了一个很好的关于Java8新特性的视频,所以就进行了学习了一下,以下是自己对 la ...

  2. JDK1.8新特性(一) ----Lambda表达式、Stream API、函数式接口、方法引用

    jdk1.8新特性知识点: Lambda表达式 Stream API 函数式接口 方法引用和构造器调用 接口中的默认方法和静态方法 新时间日期API default   Lambda表达式     L ...

  3. Java8 新特性 Lambda & Stream API

    目录 Lambda & Stream API 1 Lambda表达式 1.1 为什么要使用lambda表达式 1.2 Lambda表达式语法 1.3 函数式接口 1.3.1 什么是函数式接口? ...

  4. 十分钟学会Java8的lambda表达式和Stream API

    01:前言一直在用JDK8 ,却从未用过Stream,为了对数组或集合进行一些排序.过滤或数据处理,只会写for循环或者foreach,这就是我曾经的一个写照. 刚开始写写是打基础,但写的多了,各种乏 ...

  5. 十分钟学会Java8:lambda表达式和Stream API

    Java8 的新特性:Lambda表达式.强大的 Stream API.全新时间日期 API.ConcurrentHashMap.MetaSpace.总得来说,Java8 的新特性使 Java 的运行 ...

  6. Java8的lambda表达式和Stream API

    一直在用JDK8 ,却从未用过Stream,为了对数组或集合进行一些排序.过滤或数据处理,只会写for循环或者foreach,这就是我曾经的一个写照. 刚开始写写是打基础,但写的多了,各种乏味,非过来 ...

  7. Java 函数式编程(Lambda表达式)与Stream API

    1 函数式编程 函数式编程(Functional Programming)是编程范式的一种.最常见的编程范式是命令式编程(Impera Programming),比如面向过程.面向对象编程都属于命令式 ...

  8. Java 8新特性(Lambda,Stream API)

    由于最近总监要求学习Java 8的一些知识,就去网上找了 一套教程来学习学习,将学习结果做一个小的总结记录,方便以后使用: 1.Java 8的优点 2.Lambda表达式优点 2.1Lambda实例 ...

  9. Java 8新特性:新语法方法引用和Lambda表达式及全新的Stream API

    新语法 方法引用Method references Lambda语法 Lambda语法在AndroidStudio中报错 Stream API 我正参加2016CSDN博客之星的比赛 希望您能投下宝贵 ...

随机推荐

  1. 软件包.deb的安装及卸载------dpkg

    文章链接:https://blog.csdn.net/qq_36764147/article/details/81332606 删除带有rc的软件包:https://blog.csdn.net/chr ...

  2. GZip、deflate和sdch压缩(网摘整理)

    GZip和deflate: gzip是一种数据格式,默认且目前仅使用deflate算法压缩data部分:deflate是一种压缩算法,是huffman编码的一种加强. deflate与gzip解压的代 ...

  3. SpriteKit 学习体会贴(不断完善中)

    1. 关于 SKShapeNode 刚接触SpriteKit时,看到这个类,以为它会比SKSpriteNode更为轻量级,但其实不是: Shape nodes are useful for conte ...

  4. C#一元二次方程

  5. ob_start用法详解

    用PHP的ob_start(); 一. 相关函数简介:1.Flush:刷新缓冲区的内容,输出.函数格式:flush()说明:这个函数经常使用,效率很高.2.ob_start :打开输出缓冲区函数格式: ...

  6. NHibernate入门

    这里是官方的Demo,可以看看,因为我也是通过官方的demo学习的.   https://github.com/nhibernate/nhibernate-core/tree/master/src/N ...

  7. 如何在PDF中添加水印,PDF添加水印技巧

    PDF文件现在的使用很是普遍,不管是工作中还是学习中都会使用到PDF文件,制作一个PDF文件就很辛苦的,我们要是想把PDF文件中添加水印防止抄袭的时候应该要怎么做呢,其实吧PDF文件添加水印还挺简单的 ...

  8. 基于kali linux无线网络渗透测试

    1.无线网络渗透测试目前主要有三种方式,分别是暴力破解PIN码,跑握手包,搭建伪热点三种方式,当然还存在其他的方式. 1.1暴力破解 路由器的PIN码由八位0-9的数字组成,PIN码由散步风组成,前四 ...

  9. C++ GetUserName()

    关于函数“GetUserName()”,参见:https://msdn.microsoft.com/en-us/library/windows/desktop/ms724432(v=vs.85).as ...

  10. (转)CSS3之pointer-events(屏蔽鼠标事件)属性说明

    我们在 HTML 开发时可能会遇到这样的情况:页面上有一些元素使用绝对定位布局,这些元素可能会遮盖住它们位置下方的某个元素的部分或者全部.默认情况下,下方元素被遮挡的部分是不会响应鼠标事件的. 但有时 ...