关于java:JDK8-新特性一文搞定👍

Java8 新个性

2021/11/22
学习来源于 B站 尚硅谷yyds Java学习源码

  • 间隔,过年还有 57 天,想家~🙃
  • JDK1.8曾经公布很久了,在很多企业中都曾经在应用
  • 尽管,JDK是向下兼容的不会新个性也一样能够失常开发,然而作为程序员还是要不断更新新的技术. 不要求啥都会,但要求能看懂!😘

Java 8 是oracle公司于2014年3月公布

  • 是自Java 5 以 来最具革命性的版本
  • Java 8为Java语言: 编译器、类库、开发 工具与JVM带来了大量新个性.

Lambda表达式

函数式编程

  • Lambda表达式,最早是Python 的语法,简洁柔美,一行代码就是一个办法~

    但,说实话可读性 并不是很好 第一次看到这个时候我都懵😵了. 为了不被共事讥嘲,连夜学习了JDK8

  • Lambda 表达式,也可称为闭包 Java 8 公布的最重要新个性

    闭包: 闭包,就是可能读取其余函数外部变量的函数,例如JS中,只有函数外部的子函数能力读取局部变量

    所以:闭包,能够了解成 “定义在一个函数外部的函数“

  • Lambda 容许把函数作为一个办法的参数(函数作为参数传递进办法中 👍

根本语法:

/**Lambda语法:*/
    (参数列表) -> { 代码块 }

/**阐明:*/
/*Lambda表达式是前提基于:函数式接口来实现的: 只蕴含一个形象办法的接口,称为函数式接口 */
    左侧:指定了 Lambda 表达式须要的参数列表
    右侧:指定了 Lambda 体,是形象办法的实现逻辑,也即Lambda 表达式要执行的性能

Lambda实例:

LambdaTest.Java

  • 以 Runnable接口举例: lambda表达式, 就是 匿名实现类 的,另一种优化申明形式:
@Test
public void test1(){
/** JDK8之前,定义Runnable 接口实现多线程.*/
    //1.  类——>实现Runnable接口,创立实例...填入Thread(Runnable r); .start(); 启动线程
    //2.  匿名外部类形式,获取Runnable 接口实例: 创立一个接口实例
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("匿名外部类实现Runnable 接口实例");
        }
    };
    Thread thread1 = new Thread(runnable);
    thread1.start();

/**JDK8之后,定义Runnable Lambda接口实现多线程.*/
    //Lambda
    //  ->左侧: 指定了 Lambda 表达式须要的参数列表, 这里参数列表是空
    //  ->右侧: 指定了 Lambda 体,是形象办法的实现逻辑,也即Lambda 表达式要执行的性能;
    Runnable runnable2 = () -> { System.out.println("Lambda实现Runnable 接口实例");};
    Thread thread2 = new Thread(runnable2);
    thread2.start();
    
    //Lambda 优化:
    //  lambda形参列表的参数类型能够省略(类型推断), 如果lambda形参列表只有一个参数,  其一对()也能够省略
    //  lambda体应该应用一对{}包裹, 如果lambda体只有一条执行语句,可能是return语句, 能够省略这一对{}和return关键字.
    Runnable runnable3 = () -> System.out.println("Lambda优化实现Runnable 接口实例");
    Thread thread3 = new Thread(runnable3);
    thread3.start();
    
    System.out.println();
    System.out.println("创立的 Runnable接口实例,失常应用!");
}

控制台后果集:

匿名外部类实现Runnable 接口实例
Lambda实现Runnable 接口实例

创立的 Runnable接口实例,失常应用!
Lambda优化实现Runnable 接口实例

练习:LambdaTest.Java

@Test
public void test2(){
    /** 练习: Comparator 定制排序
         *      Comparator接口,也是一个 "函数式接口": 只蕴含一个形象办法的接口,称为函数式接口
         */
        /** JDK8之前,定义Runnable 接口实现多线程.*/
        System.out.println("天然排序/定制排序: 比拟根本/援用数据类型,A>B=1 A<B=-1 A==B=0");
        Comparator<Integer> com1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1,o2);
            }
        };
        System.out.println("定制排序1: "+com1.compare(1, 2));


        /**JDK8之后,定义Runnable Lambda接口实现多线程.*/
        //Lambda
        Comparator<Integer> com2 = (Integer o1, Integer o2) -> { return Integer.compare(o1,o2); };
        System.out.println("定制排序2: "+com2.compare(3, 2));

        //Lambda 优化:
        //类型推断: 省略类型
        //如果lambda体只有一条执行语句,可能是return语句, 能够省略这一对{}和return关键字.
        Comparator<Integer> com3 = (o1,o2) ->  Integer.compare(o1,o2);
        System.out.println("定制排序3: "+com3.compare(4, 3));

        /** 办法援用 */
        Comparator<Integer> com4 = Integer :: compare;      //前面介绍
        System.out.println("定制排序4: "+com4.compare(2, 2));
}
天然排序/定制排序: 比拟根本/援用数据类型A>B=1 A<B=-1 A==B=0
定制排序1: -1
定制排序2: 1
定制排序3: 1
定制排序4: 0

总结👍:

Lambda表达式:依赖于函数式接口, 是对函数式接口的,另一种:实例化模式~👍 更简洁,难懂🙃

->左侧: 指定了 Lambda 表达式须要的参数列表

  • lambda形参列表的参数类型能够省略 (类型推断)
  • 如果,lambda形参列表只有一个参数, 其一对 ()也能够省略

->右侧: 指定了 Lambda 体,是形象办法的实现逻辑,也即Lambda 表达式要执行的性能

  • lambda体应该应用一对{}包裹
  • 如果lambda体只有一条执行语句,可能是return语句, 能够省略这一对{}和return关键字. 省略return时候也要省略 {}

场景:

  • 能够在,将 函数式接口的实例作 自定义办法的入参进行传递,实现一些办法外部不便操作…
  • 间接定义函数式接口,调用外部的办法实现某些操作~

函数式接口:

只蕴含一个形象办法的接口,称为函数式接口

  • JDK8.0 能够通过Lambda表达式,来创立该接口的对象~ 所有的 函数式接口 都能够通过Lambda表达式类进行 实例化~

@FunctionalInterface 注解

  • JDK8.0提供一个注解来标识治理:

    该注解, 能够检 查它是否是一个函数式接口,同时 Javadoc 也会蕴含一条申明,阐明这个 接口是一个函数式接口.

  • JDK8 Java.util.function包下定义了Java 8 的丰盛的函数式接口

    为了不便不同状况的,lambda表达式的应用场景~

函数式接口实例:

Runnable接口举例:ctrl+单机 进入源码:

  • 一个接口,只有一个abstract形象办法 @FunctionalInterface 注解 润饰.

自定义函数式接口:

WsmInterface.Java

/** 注解能够省略,没有影响,注解只是对程序编写的一个揭示标识~
 *  提醒你: 这是一个函数式接口! */
@FunctionalInterface
public interface WsmInterface {
    public abstract void show();
}

Java.util.function 包:

JDK8.0 之后专门为了,Lambda 不同场景提供的不同的函数式接口

Java 内置四大外围函数式接口:

函数式接口 参数类型 返回类型 用处
Consumer< T >
消费型接口
T void 对类型为T的对象利用操作
void accept(T t)
Supplier< T >
供应型接口
T 返回类型为T的对象
T get()
Function<T, R>
函数型接口
T R 对类型为T的对象利用操作,并返回是R类型的对象.
R apply(T t)
Predicate< T >
判定型接口
T Boolean 确定类型为T的对象是否满足某束缚, 返回boolean 值<br/>boolean test(T t)

其余接口:

四大外围函数式接口:

LambdaTest2.Java

import org.junit.Test;
import java.util.function.Consumer;

/** 四大外围函数式接口Function */
public class LambdaTest2 {
/** 失常状况下,函数式接口 实例,当作办法参数传递在办法中实现事件~ */

/** 消费型接口 Consumer<T>     void accept(T t) */
    /** ① 申明一个办法传入Consumer<T> 对象实例:  */
    public void con(Double money, Consumer<Double> con){        //<T> 泛型标准了传入的类型~ Double~
        /** ②办法内,应用Consumer<T>类型参数,调用,它对应的办法,还有本人办法外部的一下操作~  */
        System.out.println("con办法调用~");
        con.accept(money);
        System.out.println("");
    };
/** ③实现 */
    /** J8前 */
    @Test
    public void ConsumerTest(){
        //要传入的参数!
        Double dd = 540.0;
        System.out.println("调用 con(Double,Consumer<Double>) 办法");

        //形式一 创立函数式接口的对象,传入接口的实例: (创立形式,匿名外部类~
        Consumer<Double> con1 = new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("接口实例类,参数传递实现: 身上还有"+aDouble+"块钱!");
            }
        };
        //调用办法
        this.con(dd,con1);

        //形式二: 参数匿名外部类实现
        this.con(dd, new Consumer<Double>() {
            @Override
            public void accept(Double adouble) {
                System.out.println("匿名外部类实现: 身上还有"+adouble+"块钱!");
            }
        });
    }

    /** J8后 */
    @Test
    public void ConsumerTest2(){
        //要传入的参数!
        Double dd = 540.0;

        //JDK8 后Lambda表达式,对 参数匿名外部类 的降级
        /** 调用 con(Double,Consumer<Double>) 办法 */
        this.con(dd, (adouble) -> System.out.println("Lambda表达式实现: 身上还有"+adouble+"块钱!") );
    }
}
# ConsumerTest  运行
调用 con(Double,Consumer<Double>) 办法
con办法调用~
接口实例类,参数传递实现: 身上还有540.0块钱!

con办法调用~
匿名外部类实现: 身上还有540.0块钱!

# ConsumerTest2 运行
con办法调用~
Lambda表达式实现: 身上还有540.0块钱!
  • Java.util.function 包下就是,JDK8为了不便用户操作,二提供的一系列的 函数式接口
  • Consumer< T >

    就是一种 函数式接口,能够 定义一个办法,应用该类型 Consumer<T> 作为参数进行办法实现… 实现一些操作.

办法/结构器/数组 援用:

一种更加 高级 的Lambda表达式 的表现形式 实质上就是一种Lambda表达式的 “语法糖”🍬

  • 当要传递给Lambda体的操作,曾经有实现的办法了,能够应用办法援用
  • 要求:

    实现接口的形象办法的 参数列表返回值 类型,必须与办法援用的办法的参数列表和返回值类型保持一致!👍

  • 语法格局:

    应用操作符 :: 将类(或对象) 与 办法名分隔开来

  • 三种场景:

    对象 :: 实例办法名

    类 :: 静态方法名

    类 :: 实例办法名

总结:👍

实现接口的形象办法的 参数列表返回值 类型, **须与办法援用的办法的参数列表和返回值类型保持一致!👍

也能够了解,办法援用就是更加,简化了Lambda的操作,如果有一个类曾经实现了 “函数式接口的办法”`

假如有一个函数式接口A
    函数式接口A
        外部办法 af();    

lambda表达式创立 A 的实例
    A a = () -> { 办法外部的操作... }
    
如果 函数式接口 外部的办法,曾经有一个B类bf()对其进行了实现,则能够在办法外部间接通过: B对象.bf(); 一行实现办法的调用
    A a = () -> { 
        B b = new B();
        b.bf();
    }
办法援用 简化降级: 
    B b = new B();        创立B类的 对象;
    A a = b::bf;        放法援用的 对象::实例办法名 援用;     省略办法的参数列表...        

留神:

  • 实现接口的形象办法的 参数列表返回值 类型,必须与办法援用的办法的参数列表和返回值类型保持一致!👍

    这样: 对象/类 :: 办法名 前面不须要跟着 (参数列表) ,因为函数式接口的办法, 和 实现类办法的 “参数列表统一能够省略...”

对象 :: 实例办法名

com.wsm.met 包下:

A 接口

/** 自定义函数式: */
@FunctionalInterface
public interface A {
    //下面实例是一个 无参, 这里定义一个有参的办法();
    public void af(int i);
}

B类 实现

/** 自定义类,实现函数式接口 */
public class B {
    //办法参数列表,与函数式接口雷同~
    public void bf(int i){
        System.out.println("对象::实例办法援用 参数列表i="+i);
    }
}

MethodTest类 办法援用测试类

import org.junit.Test;
/** 办法援用测试类 */
public class MethodTest {
/** JDK1.8之前创立A接口实例: */
    @Test
    public void Test(){
        A a = new A() {
            @Override
            public void af(int i) {
                System.out.println("JDK8之前实现接口~ 参数列表i="+i);
            }
        };

        a.af(1);
    }

/** Lambda表达式创立A接口实例: */
    @Test
    public void Test2(){
        //Lambda示意式实现A接口:
        A a =  i ->  System.out.println("Lambda表达式实现接口 参数列表i="+i);

        int i = 2;
        a.af(i);
    }

/** 对象 :: 非静态方法 */
    /** 降级Lambda表达式: 办法援用 */
    @Test
    public void Test3(){
    //① 创立B  类对象;
        B b = new B();
    //② 办法援用:
        A a = b::bf;
    //③ 调用办法~
        a.af(3);
        /** 因为 af(i) 和 bf(i) 办法实现`af实现的操作bf曾经实现了` 返回值 参数列表雷同~  */
        /** 则满足办法援用,间接应用! */
    }
}

cmd

Test
JDK8之前实现接口~ 参数列表i=1

Test2
Lambda表达式实现接口 参数列表i=2

Test3
对象::实例办法援用 参数列表i=3

类 :: 静态方法名

对象 :: 实例办法名 Demo测试扩大~

B类 扩大

//类的静态方法, bsf(int i);
public static void bsf(int i){
    System.out.println("类::static静态方法援用 参数列表i="+i);
}

MethodTest类 扩大

/** 类 :: 静态方法 */
@Test
public void Test4(){
    System.out.println("Test4");
    //① 办法援用:
    A a = B::bsf;           //间接通过 类::匹配的静态方法()~
    //② 调用办法~
    a.af(4);
}

cmd

Test4
类::static静态方法援用 参数列表i=4

总结👍

  • 对象 :: 非静态方法类 :: 静态方法
  • 实现都相似, 一个通过 对象.实例办法~ 一个 通过类.静态方法 而,类.实例办法 有点不同~

类 :: 实例办法名

MethodTest.Java

/** 类 :: 实例办法  (有难度) */
    /** 以Comparator 办法举例: int comapre(T t1,T t2) 办法 */
    /** String中的int t1.compareTo(t2) */
    @Test
    public void Test5(){
        System.out.println("Test5");
        /** lambda表达式实现 */
        Comparator<String> com1 = (s1, s2) -> s1.compareTo(s2);
        System.out.println("lambda比拟两个字符串大小~"+com1.compare("abc","abd"));

        Comparator<String> com2 = String :: compareTo;
        System.out.println("办法援用: 类 :: 实例办法 比拟两个字符串大小~"+com2.compare("abc","abd"));

        /**
         * 如果:
         *  A 函数式接口的的实现来源于~
         *    af(T1,T2);   T1类.办法(T2); 实现,则属于 类::实例办法;  的办法援用~
         * */
    }

cmd

Test5
lambda比拟两个字符串大小~-1
办法援用: 类 :: 实例办法 比拟两个字符串大小~-1

类::实例办法 的办法援用, 须要通过, 函数式接口的办法(T1,T2) 参数列表: T1类型.实例办法(T2参数); 实现“函数式接口的实现!”

结构器援用

B.Java 扩大

public String name = "default";

public B(){
    System.out.println("B() 无参结构");
}

public B(String name) {
    System.out.println("B(name,age) 有参结构");
    this.name = name;
}
//省略get/set

ConstructorRefTest.Java

/** 结构器援用 */
    //JDK8提供的函数式接口 Supplier中的T get()  返回一个 T 类型对象
    //B 类的空参结构器: B()
    public void Test(){
        /** JDK8之前 */
        Supplier<B> supB = new Supplier<B>() {
            @Override
            public B get() {
              return new B();
            };
        };
        System.out.println("JDK8之前");
        System.out.println("无参默认创立的对象: supB.get().getName();"+supB.get().getName());

        /** Lambda结构器援用 */
        Supplier<B>  supB1 = () -> new B();
        System.out.println("Lambda创立的对象: supB.get().getName();"+supB1.get().getName());

        Supplier<B>  supB2 = B :: new;
        System.out.println("结构器援用创立的对象: supB.get().getName();"+supB2.get().getName());
    }

/** 结构器援用2.0 */
    //Function中的R apply(T t);   Function<T, R>函数式接口,对类型为T的对象利用操作,并返回是R类型的对象
    @Test
    public void Test2(){
        System.out.println("Lambda创立的对象:");
        Function<String ,B> func1 = name -> new B(name);
        System.out.println("Lambda创立的对象: supB.get().getName()= "+func1.apply("wsm1").getName());

        System.out.println("*******\n");

        System.out.println("结构器援用创立的对象:");
        Function<String ,B> func2 = B :: new;           //参数主动匹配~
        System.out.println("Lambda创立的对象: supB.get().getName()= "+func2.apply("wsm2").getName());
    }

CMD

Test
JDK8之前
B() 无参结构
无参默认创立的对象: supB.get().getName();default
B() 无参结构
Lambda创立的对象: supB.get().getName();default
B() 无参结构
结构器援用创立的对象: supB.get().getName();default


Test2
Lambda创立的对象:
B(name,age) 有参结构
Lambda创立的对象: supB.get().getName()= wsm1
*******

结构器援用创立的对象:
B(name,age) 有参结构
Lambda创立的对象: supB.get().getName()= wsm2

总结:👍

  • 结构器援用,就是 与函数式接口相结合,主动与函数式接口中办法兼容
  • 能够把结构器援用赋值给定义的办法

留神:

  • 要求结构器参数列表要与接口中形象 办法的参数列表统一! 且办法的返回值即为结构器对应类的对象

格局: ClassName::new

数组援用:

与结构器援用相似 不具体介绍了...

@Test
public void Test3(){
    Function<Integer,String[]> func1 = length -> new String[length];
    String[] arr1 = func1.apply(5);
    System.out.println(Arrays.toString(arr1));

    System.out.println("*******************");

    Function<Integer,String[]> func2 = String[] :: new;
    String[] arr2 = func2.apply(10);
    System.out.println(Arrays.toString(arr2));
}

Stream API

java.util.stream包下

Java8中有两大最为重要的扭转。第一个是 Lambda 表达式;另外一个则 是 Stream API

  • Stream API 把真正的函数式编程格调引入到Java中 这是目前为止对Java类库最好的补充
  • Stream API能够极大提供Java程 序员的生产力,让程序员写出高效率、洁净、简洁的代码.
  • Stream 是 Java8 中解决汇合的要害抽象概念

    它能够指定你心愿对汇合进 行的操作,能够执行非常复杂的查找、过滤和映射数据等操作

    Stream API 对汇合数据进行操作,就相似于应用 SQL 执行的数据库查问,Stream API 提供了一种 高效且易于应用的解决数据的形式

为什么要应用Stream API:

  • 理论开发中,我的项目中少数数据源都来自于Mysql,Oracle等 关系性数据库
  • 而对于 Redsi MongDB 非关系性数据库 并不能提供,复杂性查问操作:过滤 分组 计算... 而这些NoSQL的数据就须要 Java层面去解决 很麻烦🙃

Stream 和 Collection 汇合的区别:

  • Collection 是一种动态的内存数据结构 基于内存的存储数据的空间
  • 而 Stream 是无关计算的CPU计算~

Stream 的操作三个步骤

创立 Stream

  • 一个数据源如:汇合、数组,获取一个流

    ①Stream 本人不会存储元素

    ②Stream 不会扭转源对象。相同,他们会返回一个持有后果的新Stream

    ③Stream 操作是提早执行的。这意味着他们会等到须要后果的时候才执行

两头操作

  • 一个两头操作链,对数据源的数据进行解决

终止操作(终端操作)

  • 一旦执行终止操作,就执行两头操作链,并产生后果。之后的Stream对象,不会再被应用

创立 Stream

Emp.Java 自定义操作实体类:

/** 自定义一个实体类: */
public class Emp {
    private int id;
    private String name;
    private int age;
    private double salary;
    //无参结构
    public Emp() {    }
    //有参结构
    public Emp(int id, String name, int age, double salary) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
    }
    //自定义操作数据集, `模仿从 Redis 数据库获取到的数据汇合!`
    public static List<Emp> getEmployees(){
        List<Emp> list = new ArrayList<>();

        list.add(new Emp(1001, "马化腾", 34, 6000.38));
        list.add(new Emp(1001, "马化腾", 34, 6000.38));
        list.add(new Emp(1002, "马云", 12, 9876.12));
        list.add(new Emp(1002, "马云", 12, 9876.12));
        list.add(new Emp(1003, "刘强东", 33, 3000.82));
        list.add(new Emp(1004, "雷军", 26, 7657.37));
        list.add(new Emp(1005, "李彦宏", 65, 5555.32));
        list.add(new Emp(1006, "比尔盖茨", 42, 9500.43));
        list.add(new Emp(1007, "任正非", 26, 4333.32));
        list.add(new Emp(1008, "扎克伯格", 35, 2500.32));
        return list;
    }
    //从新toString();
    @Override
    public String toString() {
        return "Emp{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                '}';
    }
    //省略get/set...
}    

StreamTest.Java 测试类:创立Stream

import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/** 弱小的Stream Api */
public class StreamTest {
/** 创立 Stream */
    @Test
    public void test1(){
        /** 形式一: 通过汇合: 汇合.stream/parallelStream(); 返回一个stream程序流/并行流~ */
        List<Emp> emps = Emp.getEmployees();

        //default Stream<E> stream() : 返回一个程序流
        Stream<Emp> stream = emps.stream();
        //default Stream<E> parallelStream() : 返回一个并行流
        Stream<Emp> parallelStream = emps.parallelStream();
        /** Java8 Collection接口增加了新的办法 stream()、parallelStream()、forEach()和removeIf()... */

        /** 形式二: 通过数组: Arrays.stream(数组); 返回对应的Stream流对象! */
        int[] arr = new int[]{1,2,3,4,5,6};
        //调用Arrays类的static <T> Stream<T> stream(T[] array): 返回一个流
        IntStream intstream = Arrays.stream(arr);              /** 根本数据类型返回,对应的 xxxstream  Stream流对象~ */
        Emp e1 = new Emp(1001,"Tom",34, 6000.38);
        Emp e2 = new Emp(1002,"Jerry",34, 6000.38);
        Emp[] arr1 = new Emp[]{e1,e2};
        Stream<Emp> empStream = Arrays.stream(arr1);                /** 自定类型数组,返回 Stream<自定义类型> 的Sream类型对象! */

        /** 形式三: 通过Stream的of() */
        Stream<Integer> stream3 = Stream.of(1, 2, 3, 4, 5, 6);      /** 用的少理解即可~ */
    }

    /** 形式四: 创立有限流: 通过Stream类的静态方法 iterate()迭代 generate()生成 */
    public void test2(){
        /** 两种形式: 迭代流 生成流 */
//      迭代
//      public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
        //参数 T , UnaryOperator函数式接口(外部办法: 传入参数T类型,返回T类型后果,正好用于对T的每次迭代的扭转~)

        //Stream.iterate(0, t -> t + 2).forEach(System.out::println);
        //  正文起因: 迭代流会有限的迭代上来 +2 +2 +2...
        //  .limit(10) 之取前十个数据
        //  .forEach() 完结操作! 完结时候做的事件~

        //遍历前10个偶数
        Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);

//      生成
//      public static<T> Stream<T> generate(Supplier<T> s)
        //参数 Supplier函数式接口对象, 外部办法, 返回一个T类型对象... 能够依据后一个规定有限的来生成一些数据~
        Stream.generate(Math::random).limit(10).forEach(System.out::println);       /** 生成10个小于 1 随机数! */
    }
}

总结:

创立Stream 一共有四种形式:

  • 汇合.stream/parallelStream(); 返回一个stream程序流/并行流~

    程序流:应用主线程,单线程,程序执行~

    并行流: .parallel()能够将其批改成并行流,外部以多线程并行执行工作的形式执行~

  • 通过数组: Arrays.stream(数组); 返回对应的Stream流对象!

    根本数据类型返回,对应的 xxxstream Stream流对象~

    自定类型数组,返回 Stream<自定义类型> 的Stream类型对象!

  • 通过Stream的of() 应用的少,相似于数组创立Stream流~
  • 创立有限流: 通过Stream类的静态方法 iterate()迭代 generate()生成

两头操作

创立完Stream流对象之后,就能够通过 流对象S.xx().xx().xx() 各种的两头操作,实现对 流种数据的计算: 筛选 切片 映射 排序…等操作

  • 两头操作, 是多个办法, 每个办法能够对流中的数据进行筛选计算~
  • 多个办法能够像链条一样 拼接操作~

两头操作,办法形容

方 法( ); 描 述:
筛选与切片
filter(Predicate p) 接管 Lambda , 从流中排除某些元素,传入一共 函数式接口 (办法参数,传入一个 T 返回Boolean后果)
distinct() 筛选,对流中元素进行 hashCode() 和 equals() 去除反复元素.
limit(long maxSize) 截断流,使其元素不超过给定数量
skip(long n) 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素有余 n 个,则返回一 个空流。与 limit(n) 互补
映 射
map(Function f) 接管一个函数作为参数,该函数会被利用到每个元 素上,并将其映射成一个新的元素
flatMap(Function f) 接管一个函数作为参数,将流中的每个值都换成另 一个流,而后把所有流连接成一个流
mapToInt(ToIntFunction f) 接管一个函数作为参数,该函数会被利用到每个元 素上,产生一个新的 IntStream
mapToLong(ToLongFunctionf) 接管一个函数作为参数,该函数会被利用到每个元 素上,产生一个新的 LongStream
mapToDouble(ToDoubleFunction f) 接管一个函数作为参数,该函数会被利用到每个元 素上,产生一个新的 DoubleStream
排 序
sorted() 产生一个新流,其中按天然程序排序
sorted(Comparator com) 产生一个新流,其中按比拟器程序排序

示例: Demo

StreamTest2.Java

import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/** Stream两头操作
 *      创立完Stream流对象之后,就能够通过 流对象S.xx().xx().xx() 各种的两头操作,实现对 流种数据的计算: 筛选 切片 映射 排序...等操作
 *      两头操作, 是多个办法, 每个办法能够对流中的数据进行筛选计算~
 *      多个办法能够像链条一样 拼接操作~
 * */
public class StreamTest2 {
    /** 筛选与切片 */
    @Test
    public void test1(){
        System.out.println("筛选与切片");
        //获取 emp 汇合~
        List<Emp> employees = Emp.getEmployees();
        //JDK8 Collection接口新增,foreach(); 办法: 遍历后果集操作~
        employees.forEach(System.out::println);

        //汇合创立Stream 流~
        Stream<Emp> stream = employees.stream();
        System.out.println("\nfilter: 从流中排除某些元素");
        System.out.println("练习: 查问员工表中薪资大于7000的员工信息");
        stream.filter(e->e.getSalary()>7000).forEach(System.out::println);  //filter(Predicate<T>); lambda表达式,每次传入一个流中对象,返回一共 Boolean后果,过滤掉false数据!

        /** 留神一共Stream 应用之后就不能够在次应用,流曾经敞开了... 但创立流的,汇合仍然存在~ */
//        stream.filter(e->e.getSalary()>7000).forEach(System.out::println);  //异样:stream has already been operated upon or closed 须要从新创立一共新的流~

        System.out.println("\ndistinct:筛选,对流中元素进行 hashCode() 和 equals() 去除反复元素");
        employees.stream().distinct().forEach(System.out::println);

        System.out.println("\nlimit(n)——截断流,使其元素不超过给定数量(获取前几个元素~)");
        employees.stream().limit(3).forEach(System.out::println);

        System.out.println("\nskip(n) —— 跳过元素(跳过前几个元素不要~)");
        employees.stream().skip(3).forEach(System.out::println);
    }

    /** **映 射** */
    @Test
    public void test2(){
        System.out.println("映射");
        System.out.println("\nmap(Function f): ——接管一个函数作为参数,将元素转换成其余模式或提取信息,该函数会被利用到每个元素上,并将其映射成一个新的元素");
        List<String> strlist = Arrays.asList("aa", "bb", "cc", "dd");
        strlist.stream().map(str -> str.toUpperCase()).forEach(System.out::println);   //遍历每一个元素,对元素进行二次操作~

        System.out.println("\n过年了,给所有员工工资+1000");
        //获取 emp 汇合~
        List<Emp> employees = Emp.getEmployees();
        System.out.println("遍历一遍汇合:");
        employees.stream().forEach(System.out::println);
        System.out.println("\n加薪: map( 外部函数式接口办法,要求传入什么参数类型,则返回什么类型~ ); 顺便去重 distinct()");
        employees.stream().map(emp -> {emp.setSalary(emp.getSalary()+1000.0); return emp; }).distinct().forEach(System.out::println);

        System.out.println("\nflatMap(f); 是map(f)的高级版~");
        System.out.println("1.Map(f) 实现遍历每一个strlist 的字符");
        Stream<Stream<Character>> streamStream = strlist.stream().map(StreamTest2::fromStringToStream);
        streamStream.forEach(s ->{
            s.forEach(System.out::println);
        });
        System.out.println("2.flatMap(f) 实现遍历每一个strlist 的字符");
        Stream<Character> characterStream = strlist.stream().flatMap(StreamTest2::fromStringToStream);
        characterStream.forEach(System.out::println);
        System.out.println("flatMap 会将,外部的每一个元素进行操作,如果是Stream元素也会从新拆开执行~");

        System.out.println("\n上面的映射,就不具体介绍了: mapToInt(T) mapToLong(T) mapToDouble(T) 传入泛型T 返回对应的相似数据~");
    }

    /** 将字符串中的多个字符形成的汇合转换为对应的Stream的实例 */
    public static Stream<Character> fromStringToStream(String str){
        ArrayList<Character> list = new ArrayList<>();
        for(Character c : str.toCharArray()){
            list.add(c);
        }
        return list.stream();
    }

    /** flatMap 和 Map :就相似于,数组外面套数组 汇合外面套汇合 遍历数组和汇合的所有元素~*/
    @Test
    public void flat(){
        ArrayList list1 = new ArrayList();
        list1.add(1);
        list1.add(2);
        list1.add(3);

        ArrayList list2 = new ArrayList();
        list2.add(4);
        list2.add(5);
        list2.add(6);
        /** map 就相当于是 add(汇合) */
//        list1.add(list2);
        /** flatMap 就相当于是 addAll(汇合) 将汇合拆分,对每个独自的元素进行操作~*/
//        list1.addAll(list2);
        System.out.println(list1);
    }


    /** 排序 */
    @Test
    public void test3(){
        System.out.println("sorted()——天然排序");
        System.out.println("留神,如果是自定义类型须要,实现Comparable接口,int 默认实现了Comparable");
        List<Integer> list = Arrays.asList(12, 43, 65, 34, 87, 0, -98, 7);
        list.stream().sorted().forEach(System.out::println);

        System.out.println("sorted(Comparator com)——定制排序");
        list.stream().sorted((e1,e2)->-e1.compareTo(e2)).forEach(System.out::println);
        /**
         * 排序 A 比拟 B
         *  返回 0  A相等B
         *  返回 -1 A小于B
         *  返回 1  A大于B
         * */
    }
}

终止操作(终端操作)

每个Stream流都是有三个步骤:创立 两头操作 终止操作

  • 一共Stream一旦调用了终止操作 就示意改Strema 对象,敞开了, 就不能够在进行操作~
  • 同样,一共没有调用 终止操作 的Stream 是不会完结的, 始终占用系统资源~
  • 终端操作会从流的流水线生成后果,==其后果能够是任何不是流的值,例 如:List、Integer== 流进行了终止操作后,不能再次应用
办法 形容
匹配与查找
allMatch(Predicate p) 查看是否匹配所有元素
anyMatch(Predicate p) 查看是否至多匹配一个元素
noneMatch(Predicate p) 查看是否没有匹配所有元素
findFirst() 返回第一个元素
findAny() 返回以后流中的任意元素
count() 返回流中元素总数
max(Comparator c) 返回流中最大值
min(Comparator c) 返回流中最小值
forEach(Consumer c) 外部迭代(应用 Collection 接口须要用户去做迭代,称为内部迭代)
Stream API 应用外部迭 代——它帮你把迭代做了)
归 约
reduce(T iden, BinaryOperator b) 能够将流中元素重复联合起来,失去一 个值,返回 T
reduce(BinaryOperator b) 能够将流中元素重复联合起来,失去一 个值,返回 Optional< T >
收 集collect⭐
collect(Collector c) 将流转换为其余模式。接管一个 Collector 接口的实现,用于给Stream中元素做汇总 的办法

collect(Collector c)

Collector 接口中办法的实现决定了如何对流执行收集的操作:

  • 如收集到 List、Set、 Map
  • Collectors 实用类提供了很多静态方法

    能够不便地创立常见收集器实例, 具体方法与实例如下表:

办法 返回类型 作用 示例:
toList List< T > 把流中元素收集到List List emps= list.stream().collect(Collectors.toList());
toSet Set< T > 把流中元素收集到Set Set emps= list.stream().collect(Collectors.toSet());
toCollection Collection< T > 把流中元素收集到创立的汇合 Collection emps =list.stream().collect(Collectors.toCollection(ArrayList::new));
counting Long 计算流中元素的个数 long count = list.stream().collect(Collectors.counting());
summingInt Integer 对流中元素的整数属性求和 int total=list.stream().collect(Collectors.summingInt(Employee::getSalary));
averagingInt averagingInt 计算流中元素Integer属性的平均值 double avg = list.stream().collect(Collectors.averagingInt(Employee::getSalary));
summarizingInt IntSummaryStatistics 收集流中Integer属性的统计值
如:平 均值
int SummaryStatisticsiss= list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
办法                返回类型               作用                                   示例:

joining             String                 连贯流中每个字符串
String str= list.stream().map(Employee::getName).collect(Collectors.joining());

maxBy                 Optional<T>         依据比拟器抉择最大值
Optional<Emp>max= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));

minBy                 Optional<T>         依据比拟器抉择最小值
Optional<Emp> min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));

reducing             归约产生的类型            从一个作为累加器的初始值开始,利用BinaryOperator与流中元素一一联合,从而归约成单个值
int total=list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum));

collectingAndThen     转换函数返回的类型        包裹另一个收集器,对其后果转换函数
int how= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));

groupingBy             Map<K, List<T>>       依据某属性值对流分组,属性为K,后果为V
Map<Emp.Status, List<Emp>> map= list.stream().collect(Collectors.groupingBy(Employee::getStatus));

partitioningBy         Map<Boolean, List<T>> 依据true或false进行分区
Map<Boolean,List<Emp>> vd = list.stream().collect(Collectors.partitioningBy(Employee::getManage));

示例:Demo

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/** 终止操作 */
public class StreamTest3 {

    @Test
    public void test(){
        System.out.println("匹配与查找\n");
        List<Emp> employees = Emp.getEmployees();
//        allMatch(Predicate p)——查看是否匹配所有元素。
//          练习:是否所有的员工的年龄都大于18
        boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 18);
        System.out.println(allMatch);

//        anyMatch(Predicate p)——查看是否至多匹配一个元素。
//         练习:是否存在员工的工资大于 10000
        boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() > 10000);
        System.out.println(anyMatch);

//        noneMatch(Predicate p)——查看是否没有匹配的元素。
//          练习:是否存在员工姓“雷”
        boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("雷"));
        System.out.println(noneMatch);
//        findFirst——返回第一个元素
        Optional<Emp> employee = employees.stream().findFirst();
        System.out.println(employee);
//        findAny——返回以后流中的任意元素
        Optional<Emp> employee1 = employees.parallelStream().findAny();
        System.out.println(employee1);
    }

    @Test
    public void test2(){
        List<Emp> employees = Emp.getEmployees();
        // count——返回流中元素的总个数
        long count = employees.stream().filter(e -> e.getSalary() > 5000).count();
        System.out.println(count);
//        max(Comparator c)——返回流中最大值
//        练习:返回最高的工资:
        Stream<Double> salaryStream = employees.stream().map(e -> e.getSalary());
        Optional<Double> maxSalary = salaryStream.max(Double::compare);
        System.out.println(maxSalary);
//        min(Comparator c)——返回流中最小值
//        练习:返回最低工资的员工
        Optional<Emp> employee = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
        System.out.println(employee);
        System.out.println();
//        forEach(Consumer c)——外部迭代
        employees.stream().forEach(System.out::println);

        //应用汇合的遍历操作
        employees.forEach(System.out::println);
    }

    //2-归约
    @Test
    public void test3(){
//        reduce(T identity, BinaryOperator)——能够将流中元素重复联合起来,失去一个值。返回 T
//        练习1:计算1-10的自然数的和
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        Integer sum = list.stream().reduce(0, Integer::sum);
        System.out.println(sum);


//        reduce(BinaryOperator) —— 函数式接口对象——>能够将流中元素重复联合起来,失去一个值,返回 Optional<T>
//        练习2:计算公司所有员工工资的总和
        List<Emp> employees = Emp.getEmployees();
        Stream<Double> salaryStream = employees.stream().map(Emp::getSalary);
        Optional<Double> sumMoney = salaryStream.reduce((d1,d2) -> d1 + d2);
        System.out.println(sumMoney.get());

    }

    //3-收集
    @Test
    public void test4(){
//        collect(Collector c)——将流转换为其余模式。接管一个 Collector接口的实现,用于给Stream中元素做汇总的办法
//        练习1:查找工资大于6000的员工,后果返回为一个List或Set
        List<Emp> employees = Emp.getEmployees();
        List<Emp> employeeList = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
        employeeList.forEach(System.out::println);

        System.out.println();
        Set<Emp> employeeSet = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
        employeeSet.forEach(System.out::println);
    }

}

Optional 类

Java利用中最常见的bug就是[空值异样]()

  • 在Java 8之前,Google Guava引入了Optionals类来解决NullPointerException从而防止源码被各种**null**查看净化,以便开发者写出更加整洁的代码
  • Java 8也将Optional退出了官网库

Optional 类(java.util.Optional) 是一个容器类

  • 就是对一共对象,的一共包装~ 保障调用对象之后不会产生 空指针

    它能够保留类型T的值,代表这个值存在,或者仅仅保留null,示意这个值不存在

罕用办法:

创立Optional类对象的办法

  • Optional.of(T t) : 创立一个 Optional 实例,t必须非空
  • Optional.empty() : 创立一个空的 Optional 实例
  • Optional.ofNullable(T t):t能够为null

判断Optional容器中是否蕴含对象

  • boolean isPresent() : 判断是否蕴含对象
  • void ifPresent(Consumer consumer) :如果有值,就执行Consumer 接口的实现代码,并且该值会作为参数传给它

获取Optional容器的对象

  • T get(): 如果调用对象蕴含值,返回该值,否则抛异样
  • T orElse(T other) :如果有值则将其返回,否则返回指定的other对象
  • T orElseGet(Supplier other) :如果有值则将其返回,否则返回由 Supplier接口实现提供的对象
  • T orElseThrow(Supplier exceptionSupplier) :如果有值则将其返 回,否则抛出由Supplier接口实现提供的异样

接口默认办法

这个最为简略,能够简略的了解当初的接口中办法能够定默认实现

这样做到了像以前一样的形象办法实现接口的默认实现,也不便了咱们不在须要像以前一样做形象的模板模式

interface A{
    defalut void method1(){
        method2(); //默认实现
    }
    void method2();
}

java8接口中除了default method,还提供定义(并实现)静态方法

interface B{
    static String method(){
        return "xxx";
    }
}

注解的影响:

自己的注解学习~

新日期API

自己罕用类学习

其它新增:

Base64 加解密:

Java 8将Base64 退出到JDK库中 样不须要应用第三方库就能够进行Base64编码

import java.nio.charset.StandardCharsets;
import java.util.Base64;
/** Base64 加解密 */
public class Base {
    public static void main(String[] args) {
        final String text = "Java慈爱,yyds!";

        final String encoded = Base64.getEncoder().encodeToString( text.getBytes( StandardCharsets.UTF_8 ) );
        System.out.println("加密:"+encoded);

        final String decoded = new String(Base64.getDecoder().decode( encoded ),StandardCharsets.UTF_8 );
        System.out.println("解密:"+decoded);
    }
}

MD5 加解密:

尽然提到加密就顺便题一下MD5 加密:

  • MD5的全称是Message-Digest Algorithm信息-摘要算法
  • MD5其实不算是加密算法,而是一种信息的摘要,它的个性是不可逆的 除了暴力破解 个别逆序算法是得不到后果的一个个试验暴力循环~

举个例子:

  • 1+99=100

    MD5接到的字符是1和99 而后通过本人的算法最初生成100 但晓得后果是100却很难揣测出是通过1+99得来的

  • 再比方 一本书的每一页取一个字,最初通过计算得出一个MD5码

    但却很难通过这个MD5码去揣测出这本书的内容…

MD5加密的特点次要有以下几点:

  • 针对不同长度待加密的数据、字符串等等,其都能够返回一个固定长度的MD5加密字符串
  • 其加密过程简直不可逆,除非保护一个宏大的Key-Value数据库来进行碰撞破解,否则简直无奈解开
  • 对于一个固定的字符串。数字等等,MD5加密后的字符串是固定的,也就是说不论MD5加密多少次,都是同样的后果

java.security.MessageDigest

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/** Md5加密 */
public class Md5 {
    public static void main(String[] args) throws NoSuchAlgorithmException {
        // 生成一个MD5加密计算摘要
        MessageDigest md = MessageDigest.getInstance("MD5");

        md.update("Java.慈爱,yyds".getBytes());
        //digest()最初确定返回md5 hash值,返回值为8位字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
        //BigInteger函数则将8位的字符串转换成16位hex值,用字符串来示意;失去字符串模式的hash值
        //一个byte是八位二进制,也就是2位十六进制字符(2的8次方等于16的2次方)
        System.out.println(new BigInteger(1, md.digest()).toString(16));
    }
}

MD5 简略的字符串加密之后能够在线解密,简单的话解不进去的 在线解密

UUID 🐶

UUID 是Java1.5 就新增的~

  • UUID是指在一台机器上生成的数字,它保障对在同一时地面的所有机器都是惟一的

UUID由以下几局部的组合:

  1. 以后日期和工夫,UUID的第一个局部与工夫无关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个局部不同,其余雷同
  2. 时钟序列
  3. 全局惟一的IEEE机器辨认号,如果有网卡,从网卡MAC地址取得,没有网卡以其余形式取得
import java.util.UUID;

String uuid = UUID.randomUUID().toString();

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理