Java8新特性

Java8新特性

Lambda表达式

概念

lambda表达式是一段可以传递的代码,它的核心思想是将面向对象中的传递数据变成传递行为
允许把函数作为一个方法的参数(函数作为参数传递进方法中)
作用:使用 Lambda 表达式可以使代码变的更加简洁紧凑。

AndroidStudio 支持Lambda表达式

android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "video.uf.com.java8test"
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        jackOptions.enabled = true //支持Java8 Lambda表达式配置
    }
    //支持Java8 Lambda表达式 配置
    compileOptions{
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }


}

语法

(Type1 param1, Type2 param2, ..., TypeN paramN) -> {
statment1;
statment2;
//.............
return statmentM;
}

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
Button btn  = new Button(this);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("sss","ssss");
            }
        });
        btn.setOnClickListener(v -> Log.e("sss","ssss"));

变量作用域

lambda 表达式只能引用 final 局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。

            int count = 1;
        btn.setOnClickListener(v -> {
            count = 10;//编译错误
            Log.e("sss","ssss")});

匿名类和Lambda表达式的区别

  • 使用匿名类与 Lambda 表达式的一大区别在于关键词的使用。对于匿名类,关键词 this 解读为匿名类,而对于 Lambda 表达式,关键词 this 解读为写就 Lambda 的外部类。
  • Lambda 表达式与匿名类的另一不同在于两者的编译方法。Java 编译器编译 Lambda 表达式并将他们转化为类里面的私有函数,它使用 Java 7 中新加的 invokedynamic 指令动态绑定该方法
class TestBean {
        private TestInterface testInterface;
        public TestBean(TestInterface testInterface) {
            this.testInterface = testInterface;
        }
        public void test() {
            if (testInterface != null) {
                testInterface.test();
            }
        }
    }
interface TestInterface {
        void test();
    }
private void tt() {
        TestBean testBean = new TestBean(new TestInterface() {
            @Override
            public void test() {
                System.out.println("AnonymousClass--->" + this.getClass().getName());//video.uf.com.java8test.Test2$1
            }
        });
        testBean.test();
        TestBean testBean1 = new TestBean(() -> System.out.println("Java8--->" + this.getClass().getName()));
        //Java8--->video.uf.com.java8test.Test2
        testBean1.test();
    }

函数式接口

概念

函数式接口(Functional Interface)就是一个具有一个方法的普通接口。 @FunctionalInterface注解

特点

可以被隐式转换为lambda表达式

常用的函数式接口

java.lang.Runnable

例如:

new Thread(new Runnable() {             
          @Override
          public void run() {
              System.out.println("Create Thread before Java8");
          }
      }).start();   
new Thread(()->System.out.println("Java8-------->")).start(); 

java.util.Comparator

例如:

         List list = new ArrayList<>();
        list.add(3);
        list.add(5);
        list.add(4);
        System.out.println("origin Data");
        for(Integer item : list){
            System.out.println("---->"+item);
        }

        System.out.println("Sorted Collection before Java8");
        Collections.sort(list, new Comparator() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1-o2;
            }
        });
        for(Integer item : list){
            System.out.println("---->"+item);
        }
        list = new ArrayList<>();
        list.add(3);
        list.add(5);
        list.add(4);
        System.out.println("Sorted Collection By Java8");
        Collections.sort(list, (item1,item2)->item1-item2);
        for(Integer item : list){
            System.out.println("---->"+item);
        }

java.io.FileFilter

例如:

        File files;
        File[] file;
        try{
            files = new File("/Users/qinzongke/ShareProjects/Java8Studio/app");
            file = files.listFiles(new FileFilter() {
                @Override
                public boolean accept(File pathname) {
                    return pathname.isDirectory();
                }
            });
            for (File item : file){
                System.out.println("fileFiltertest---->"+item.getAbsolutePath());
            }
            file = files.listFiles(item->item.isFile());
            for (File item : file){
                System.out.println("fileFiltertest---->"+item.getAbsolutePath());
            }

        }catch (Exception e){

        }

Java8新增的函数接口

java.util.function
主要分为以下几个基本类别
Function 函数型接口 输入参数为类型T, 输出为类型R, 记作 T -> R
Consumer 消费型接口 输入参数为类型T, 输出为void, 记作 T -> void
Supplier 供给型接口 没有输入参数, 输出为类型T, 记作 void -> T
Predicate 断言型接口 输入参数为类型T, 输出为类型boolean, 记作 T -> boolean

static class AddNewInterface{
      private BiConsumer customer;
      private BiFunction function;
      
      public AddNewInterface(BiFunction function){
          this.function =function;
      }

      public AddNewInterface(BiConsumer customer){
          this.customer = customer;
      }

      public void getHandler1(int value1,int value2){
          if(customer != null){
              customer.accept(value1,value2);
          }
      }
      
      public int getHandler2(int value1,int value2){
          if(function != null){
              return function.apply(value1,value2);
          }
          return 0;
      }  
      
private void addNewInterfaceTest(){
        AddNewInterface interface1  = new AddNewInterface(new BiConsumer(){

            @Override
            public void accept(Integer t, Integer u) {
                // TODO Auto-generated method stub
                System.out.println("value1---->"+t);
                System.out.println("value2---->"+u);
            }
            
        });
        AddNewInterface interface2 = new AddNewInterface((value1,value2)->{
            System.out.println("Java8--->value1="+value1);
            System.out.println("Java8---->value2="+value2);
            });
        interface1.getHandler1(10,20);
        interface2.getHandler1(30, 40);
        AddNewInterface interface3 =  new AddNewInterface(new BiFunction(){

            @Override
            public Integer apply(Integer t, Integer u) {
                // TODO Auto-generated method stub
                return t*u;
            }
        });
        AddNewInterface interface4 = new AddNewInterface((value1,value2)->value1+value2);
        int count1 = interface3.getHandler2(10,20);
        System.out.println("count1---->"+count1);
        int count2 = interface4.getHandler2(10,20);
        System.out.println("count2---->"+count2);
    }

默认方法

概念

默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。
我们只需在方法名前面加个default关键字即可实现默认方法。
默认方法也可以被重写

语法

例如:

interface TestInterface{
        int add(int value1,int value2);
        default void test2(String message){
            System.out.println("TestInterface--->test2----->"+message);
        }
        default void test3(String message){
            System.out.println("TestInterface--->test3----->"+message);
        }
    }
private void defaultMethodTest(){
        TestInterface interface1 = (value1,value2)->value1+value2;
        int  count = interface1.add(10,20);
        interface1.test2("aaaaa");
        interface1.test3("bbbbb");
    }

多个默认方法

一个类实现了多个接口,且这些接口有相同的默认方法

interface TestInterface{
        int add(int value1,int value2);
        default void test2(String message){
            System.out.println("TestInterface--->test2----->"+message);
        }
        default void test3(String message){
            System.out.println("TestInterface--->test3----->"+message);
        }
    }
interface TestInterface2{
        int add(int value1,int value2);
        default void test2(String message){
            System.out.println("TestInterface2--->test2----->"+message);
        }
        default void test3(String message){
            System.out.println("TestInterface2--->test3----->"+message);
        }

    }
class TestInterfaceClass implements TestInterface,TestInterface2{
        @Override
        public int add(int value1, int value2) {
            return value1+value2;
        }

        @Override
        public void test2(String message) {
            //方法1:创建自己的默认方法,来覆盖重写接口的默认方法
            System.out.println("TestInterfaceClass---->"+message);
        }

        @Override
        public void test3(String message) {
            //方法2:使用 super 来调用指定接口的默认方法
            TestInterface2.super.test3(message);
        }
    }

静态默认方法

interface TestInterface{
        int add(int value1,int value2);
        default void test2(String message){
            System.out.println("TestInterface--->test2----->"+message);
        }
        static void test4(String message){
            System.out.println("TestInterface--->test4--->"+message);
        }
        default void test3(String message){
            System.out.println("TestInterface--->test3----->"+message);
        }
    }
private void defaultStaticMethodTest(){
        TestInterface.test4("defaultStaticMethodTest");
    }

方法引用

作用

我们通常使用lambda表达式来创建匿名方法。然而,有时候我们仅仅是调用了一个已存在的方法
方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
方法引用使用一对冒号 ::
例如:

String [] arr = {"a","c","d","b"};
Arrays.sort(arr, new Comparator() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareToIgnoreCase(o2);
            }
        });//普通方式
Arrays.sort(arr,(s1,s2)->s1.compareToIgnoreCase(s2));//lambda 方式
Arrays.sort(arr,String::compareToIgnoreCase);//方法引用方式

适用场景: 当一个Lambda表达式调用了一个已存在的方法
不适用场景: 当我们需要引用的方法传其它参数的时候,不适合,

public class MethodReferenceBean {
    
    public static void staticMethodTest(){
        System.out.println("i am static method without params");
    }
    public static void staticMethodTest2(MethodReferenceBean bean){
        System.out.println("i am static method without params");
    }
}
private void test1(){
        List list = new ArrayList<>();
        for(int i = 0;i<10;i++){
            list.add(new MethodReferenceBean());
        }
        list.forEach(new Consumer(){

            @Override
            public void accept(MethodReferenceBean t) {
                // TODO Auto-generated method stub
                MethodReferenceBean.staticMethodTest();
            }
        });
        list.forEach(item->MethodReferenceBean.staticMethodTest());//可以使用
        list.forEach(item->MethodReferenceBean.staticMethodTest2(item));//可以使用
        list.forEach(MethodReferenceBean::staticMethodTest);//不可使用
        list.forEach(MethodReferenceBean::staticMethodTest2);//可以使用;
    }

构造器引用

语法:Class::new
一般同Supplier接口联合使用 可自定义类似接口 目前Android最低支持的SDKApi为 24
注意:对目标类必须存在无参的构造方法
例如:

public class Test2 {
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub  
        Test2 testBean1 = new Test2();//方法1
        Test2 testBean2 = Test2.newInstance();//方法2
        Test2 testBean3 = Test2.newInstance(Test2::new);//方法3
    }
    
    public static Test2 newInstance(Supplier supplier){
        return supplier.get();
    }
    
    public static Test2 newInstance(){
        return new Test2();
    }
}
  • 下一步优化
public class InstanceFactory {

    public  static T getInstance(Supplier supplier){
        return supplier.get();
    }
}
public class Test2 {
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub  
        Test2 testBean1 = InstanceFactory.getInstance(Test2::new);
    }
}

针对构造方法传递参数的情况

@FunctionalInterface
public interface InstanceFactorys {
    
    T getInstance(int param1,String param2,String param3);

}
public class Test2 {
    
    private int id;
    private String name;
    private String address;
    
    public Test2(int id, String name, String address) {
        this.id = id;
        this.name = name;
        this.address = address;
    }
    
    public Test2() {
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub  
        //InstanceFactorys函数式接口 接口内至存在一个方法
        InstanceFactorys factorys = Test2::new;//必须存在无参的构造方法
        Test2 testBean = factorys.getInstance(1,"name","address");
        System.out.println("id-->"+testBean.id);
        System.out.println("name-->"+testBean.name);
        System.out.println("address-->"+testBean.address);
    }
    
}

Stream API

基本概念

本质: 对集合功能的完善,以声明的形式操作集合,它就像SQL语句,我们只需告诉流需要对集合进行什么操作,它就会自动进行操作,并将执行结果交给你,无需我们自己手写代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
例如: 获取一批学生年龄>=20并且性别为男的同学集合并按年龄降序排列打印信息

class Student {
        public String name;
        public int age;
        public int sex;// 1 男 2 女

        public Student(String name, int age, int sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
    }

/**
     * 获取学生数据源集合
     * @return
     */
    private List getDataSource() {
        List dataSource = new ArrayList<>();
        dataSource.add(new Student("test1", 5, 1));
        dataSource.add(new Student("test2", 10, 2));
        dataSource.add(new Student("test3", 15, 2));
        dataSource.add(new Student("test4", 20, 1));
        dataSource.add(new Student("test5", 5, 2));
        dataSource.add(new Student("test6", 10, 1));
        dataSource.add(new Student("test7", 15, 2));
        dataSource.add(new Student("test8", 20, 1));
        dataSource.add(new Student("test9", 25, 2));
        dataSource.add(new Student("test10", 25, 1));
        return dataSource;
    }
/**
     * Java7处理方式
     */
    private void handlerJava7() {
        List dataSource = getDataSource();
        List newData = new ArrayList();
        for (Student student : dataSource) {
            if (student.age >= 20 && student.sex == 1) {
                newData.add(student);
            }
        }
        Collections.sort(newData, new Comparator() {

            @Override
            public int compare(Student s1, Student s2) {
                // TODO Auto-generated method stub
                return s2.age - s1.age;
            }
        });
        for (Student s : newData) {
            System.out.println("name--->"+s.name+" age------>" + s.age);
        }
    }
//Sql处理
select * from student where sex=1 and age >=20 order by age desc
/**
     * Java8处理方式
     */
    private void handlerJava8() {
        List dataSource = getDataSource();
        dataSource.stream().filter(s -> s.age >= 20 && s.sex == 1).sorted((s1, s2) -> s2.age - s1.age)
                .collect(Collectors.toList()).forEach(s -> System.out.println("name--->"+s.name+" age--->" + s.age));
    }

流的操作步骤

  • 准备一个数据源
  • 执行中间操作

中间操作可以有多个,它们可以串连起来形成流水线。

  • 执行终端操作

执行终端操作后本次流结束,将获得一个执行结果

一个完整的Stream操作由零个或多个中间操作(intermediate operation)和一个结束操作(terminal operation)两部分组成。只有执行结束操作时,Stream定义的中间操作才会依次执行,
从操作的返回值来看:如果返回值是Stream,那么就是惰性求值;如果返回值不是Stream或者是void,那么就是及早求值。一个完整的Stream操作是有多个惰性求值和一个及早求值组成

流的获取

  • 集合 这种数据源较为常用,通过stream()方法即可获取流对象

对应Collection接口

//获取串形流
default Stream stream() {
        return StreamSupport.stream(this.spliterator(), false);
    }
//获取并形流
default Stream parallelStream() {
        return StreamSupport.stream(this.spliterator(), true);
    }

例如

List lists = new ArrayList<>();
Stream stream =  lists.stream();
  • 数组 通过Arrays类提供的静态函数stream()获取数组的流对象

例如:

String[] names = {"chaimm","peter","john"};
Stream stream = Arrays.stream(names);  
  • 值 直接将几个值变成流对象
Stream stream =Stream.of("test1","test2","test3");
  • 其他

generator方法,返回一个无限长度的Stream,其元素由Supplier接口的提供。在Supplier是一个函数接口,只封装了一个get()方法,其用来返回任何泛型的值,该结果在不同的时间内,返回的可能相同也可能不相同,没有特殊的要求。这种情形通常用于随机数、常量的 Stream,默认是串行(相对 parallel 而言)但无序的(相对 ordered 而言)。

 /**
     * Returns an infinite sequential unordered stream where each element is
     * generated by the provided {@code Supplier}.  This is suitable for
     * generating constant streams, streams of random elements, etc.
     *
     * @param  the type of stream elements
     * @param s the {@code Supplier} of generated elements
     * @return a new infinite sequential unordered {@code Stream}
     */
    public static Stream generate(Supplier s) {
        Objects.requireNonNull(s);
        return StreamSupport.stream(
                new StreamSpliterators.InfiniteSupplyingSpliterator.OfRef<>(Long.MAX_VALUE, s), false);
    }
/**
     * generator 生成Stream
     * 配合limit 和filter 使用 否则会无限执行
     */
    private void generatorSteam(){
        Stream.generate(()->Math.random()).limit(10).forEach(item->System.out.println("--->"+item));;
    }

iterate方法,其返回的也是一个无限长度的Stream,与generate方法不同的是,其是通过函数f迭代对给指定的元素种子而产生无限连续有序Stream,其中包含的元素可以认为是:seed,f(seed),f(f(seed))无限循环。

/**
     * Returns an infinite sequential ordered {@code Stream} produced by iterative
     * application of a function {@code f} to an initial element {@code seed},
     * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
     * {@code f(f(seed))}, etc.
     *
     * 

The first element (position {@code 0}) in the {@code Stream} will be * the provided {@code seed}. For {@code n > 0}, the element at position * {@code n}, will be the result of applying the function {@code f} to the * element at position {@code n - 1}. * * @param the type of stream elements * @param seed the initial element * @param f a function to be applied to to the previous element to produce * a new element * @return a new sequential {@code Stream} */ public static Stream iterate(final T seed, final UnaryOperator f) { Objects.requireNonNull(f); final Iterator iterator = new Iterator() { @SuppressWarnings("unchecked") T t = (T) Streams.NONE; @Override public boolean hasNext() { return true; } @Override public T next() { return t = (t == Streams.NONE) ? seed : f.apply(t); } }; return StreamSupport.stream(Spliterators.spliteratorUnknownSize( iterator, Spliterator.ORDERED | Spliterator.IMMUTABLE), false); }

/**
     * iterate生成Stream
     */
    private void iterateStream(){
        Stream.iterate(2, item->item*item).filter(item->item!=0).forEach(item->System.out.println("---->"+item));
    }

concat方法将两个Stream连接在一起,合成一个Stream。若两个输入的Stream都时排序的,则新Stream也是排序的;若输入的Stream中任何一个是并行的,则新的Stream也是并行的;若关闭新的Stream时,原两个输入的Stream都将执行关闭处理。

 /**
     * Creates a lazily concatenated stream whose elements are all the
     * elements of the first stream followed by all the elements of the
     * second stream.  The resulting stream is ordered if both
     * of the input streams are ordered, and parallel if either of the input
     * streams is parallel.  When the resulting stream is closed, the close
     * handlers for both input streams are invoked.
     *
     * @implNote
     * Use caution when constructing streams from repeated concatenation.
     * Accessing an element of a deeply concatenated stream can result in deep
     * call chains, or even {@code StackOverflowException}.
     *
     * @param  The type of stream elements
     * @param a the first stream
     * @param b the second stream
     * @return the concatenation of the two input streams
     */
    public static  Stream concat(Stream a, Stream b) {
        Objects.requireNonNull(a);
        Objects.requireNonNull(b);

        @SuppressWarnings("unchecked")
        Spliterator split = new Streams.ConcatSpliterator.OfRef<>(
                (Spliterator) a.spliterator(), (Spliterator) b.spliterator());
        Stream stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
        return stream.onClose(Streams.composedClose(a, b));
    }
/**
     * concat 组合生成Stream
     */
    private void concatStream(){
        Stream.concat(Stream.of(1,2,3),Stream.of(4,5,6)).forEach(item->System.out.println("---->"+item));
    }

串行流、并行流

串行流:操作由一个线程串行处理
并行流:把一个内容分成多个数据块,并用不同的线程分 别处理每个数据块的流
相互转换:对流使用parallel()方法将串行流转换为并行流。对流使用sequential()方法将并行流转换为串行流。

/**
     * Returns an equivalent stream that is sequential.  May return
     * itself, either because the stream was already sequential, or because
     * the underlying stream state was modified to be sequential.
     *
     * 

This is an intermediate * operation. * * @return a sequential stream */ S sequential();

/**
     * Returns an equivalent stream that is parallel.  May return
     * itself, either because the stream was already parallel, or because
     * the underlying stream state was modified to be parallel.
     *
     * 

This is an intermediate * operation. * * @return a parallel stream */ S parallel();

中间操作

中间操作负责将一个流转换为另一个流,包括 filter()(选择与条件匹配的元素)、map()(根据函数来转换元素)、distinct()(删除重复)、limit()(在特定大小处截断流)和 sorted()。

filter

对于Stream中包含的元素使用给定的过滤函数进行过滤操作,新生成的Stream只包含符合条件的元素
例如:

private void streamTest(){
        Stream.of(1,2,2,3,3,4,4,5,5,6,6,7,8,9,10).filter(item->item%2 == 0).forEach(item->System.out.println("---->"+item));
    }

distinct

返回去重的Stream

private void streamTest(){
        Stream.of(1,2,2,3,3,4,4,5,5,6,6,7,8,9,10).filter(item->item%2 == 0).distinct().forEach(item->System.out.println("---->"+item));
    }

sorted

返回一个排序的Stream。默认升序排列

private void streamTest(){
//      Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).distinct().sorted().forEach(item->System.out.println("---->"+item));
        Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).distinct().sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
    }

limit

返回前n个元素数据组成的Stream。属于短路操作

private void streamTest(){
        Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).limit(10).filter(item->item%2 == 0).distinct().sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
    }

skip

返回第n个元素后面数据组成的Stream

private void streamTest(){
        Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).skip(4).filter(item->item%2 == 0).distinct().sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
    }

map

对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。这个方法有三个对于原始类型的变种方法,分别是:mapToInt,mapToLong和mapToDouble。这三个方法也比较好理解,比如mapToInt就是把原始Stream转换成一个新的Stream,这个新生成的Stream中的元素都是int类型。之所以会有这样三个变种方法,可以免除自动装箱/拆箱的额外消耗;

private void streamTest(){
        Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).skip(4).peek(item->System.out.println("peek--->"+item)).filter(item->item%2 == 0).distinct().map(item->item*2).sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
    }

flatMap

和map类似,不同的是其每个元素转换得到的是Stream对象,会把子Stream中的元素压缩到

private void streamTest(){
        Stream.of(Arrays.asList(1,2,3),Arrays.asList(4,5,6)).flatMap(item->item.stream()).map(item->item*2).forEach(item->System.out.println("flat--->"+item));
//      Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).skip(4).peek(item->System.out.println("peek--->"+item)).filter(item->item%2 == 0).distinct().map(item->item*2).sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
    }

peek

生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数

private void streamTest(){
        Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).skip(4).peek(item->System.out.println("peek--->"+item)).filter(item->item%2 == 0).distinct().sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
    }

终端操作

数据集的处理在执行终止操作时开始,比如缩减(sum() 或 max())、应用 (forEach()) 或搜索 (findFirst()) 操作。终止操作会生成一个结果或无结果

forEach

将提供的操作应用于流的每个元素

private void streamTest(){
//      Stream.of(Arrays.asList(1,2,3),Arrays.asList(4,5,6)).flatMap(item->item.stream()).map(item->item*2).forEach(item->System.out.println("flat--->"+item));
        Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).skip(4).peek(item->System.out.println("peek--->"+item)).filter(item->item%2 == 0).distinct().map(item->item*2).sorted((item1,item2)->item2-item1).forEach(item->System.out.println("---->"+item));
    }

toArray

使用流的元素创建一个数组

Integer[] arrays = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).distinct().toArray(item-> new Integer[item]);

collect

将流的元素聚合到一个汇总结果容器中。

List array = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).distinct().collect(Collectors.toList());
Collectors

为Stream的collect提供转换类型

toList

把流中所有元素收集到List中
返回类型: List

toSet

把流中所有元素收集到Set中,删除重复项
返回类型:Set

Set array = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.toSet());
toCollection

把流中所有元素收集到给定的供应源创建的集合中
返回类型:Collection

ArrayList array = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.toCollection(()->new ArrayList()));
counting

计算流中元素个数
返回类型:long

long count = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.counting());
summingInt

对流中元素的一个整数属性求和
返回类型:Integer

int count = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.summingInt(item->item));
averagingInt

计算流中元素integer属性的平均值
返回值类型:Double

double count = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.averagingInt(item->item));
joining

连接流中每个元素的toString方法生成的字符串
返回值类型:String

String str = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).map(item->String.valueOf(item)).collect(Collectors.joining(","));
maxBy

流中按照给定比较器选出的最大元素的optional
如果为空返回的是Optional.empty()
返回值类型:Optional

Optional value = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.maxBy((item1,item2)->item1-item2));
minBy

流中按照给定比较器选出的最大元素的optional
如果为空返回的是Optional.empty()
返回值类型:Optional

Optional value = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.minBy((item1,item2)->item1-item2));
reducing

从一个作为累加器的初始值开始,利用binaryOperator与流中的元素逐个结合,从而将流归约为单个值
返回值类型:T / Optional

int value1 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.reducing(100,(item1,item2)->item1+item2));
int value2 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).collect(Collectors.reducing((item1,item2)->item1+item2)).get();
groupingBy

根据流中元素的某个值对流中的元素进行分组,并将属性值做为结果map的键
返回值类型:Map>

List datas = getDataSource();
Map> data = datas.stream().collect(Collectors.groupingBy((item1)->item1.sex));
partitioningBy

根据流中每个元素应用谓语的结果来对项目进行分区
返回值类型:Map>

Map> data = datas.stream().collect(Collectors.partitioningBy(item->item.sex==1));

reduce/min/max/count

作用类似Collectors中

int value1 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).limit(3).filter(item->item%2 == 0).reduce((item1,item2)->item1+item2).get();
int value2 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).limit(3).filter(item->item%2 == 0).reduce(100,(item1,item2)->item1+item2);
int value3 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).max((item1,item2)->item1-item2).get();
int value4 = Stream.of(1,2,2,3,3,6,6,5,4,4,5,7,8,9,10).filter(item->item%2 == 0).min((item1,item2)->item1-item2).get();

anyMatch/allMatch/noneMatch

有一个符合条件返回true/全部符合条件返回true/完全不符合条件返回true

List datas = getDataSource();
boolean flag1 = datas.stream().anyMatch(item->item.sex==1);
boolean flag2 = datas.stream().anyMatch(item->item.sex==2);
boolean flag3 = datas.stream().anyMatch(item->item.sex==3);
boolean flag4 = datas.stream().noneMatch(item->item.sex == 3);
boolean flag5 = datas.stream().noneMatch(item->item.sex==2);
boolean flag6 = datas.stream().allMatch(item->item.sex == 1);

findFirst/findAny

返回流的第一个元素(如果有)/返回流的任一个元素(如果有)

Student student1 = datas.stream().findFirst().get();
Student student2 = datas.stream().findAny().get();

Optional 类

Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
Optional 类的引入很好的解决空指针异常

class TestBean {
        public TestBean1 bean1;
        public TestBean(TestBean1 bean1) {
            this.bean1 = bean1;
        }
    }
class TestBean1 {
        public TestBean2 bean2;
        public TestBean1(TestBean2 bean) {
            this.bean2 = bean;
        }
    }
class TestBean2 {
        public String name;
        public TestBean2(String name) {
            this.name = name;
        }
    }
private void testJava7(TestBean bean) {
        if(bean != null){
            if(bean.bean1!=null){
                if(bean.bean1.bean2 != null){
                    System.out.println(bean.bean1.bean2.name);  
                }
            }
        }
    }
private void testJava8(TestBean bean) {
        Optional.ofNullable(bean).map(item->item.bean1).map(item->item.bean2).ifPresent(t->System.out.println(t.name));
    }

创建Optional对象

  • of

of方法通过工厂方法创建Optional类。需要注意的是,创建对象时传入的参数不能为null。如果传入参数为null,则抛出NullPointerException

TestBean bean = new TestBean(1,"test1",15,1);
Optional test = Optional.of(bean);
TestBean bean1 = null;
Optional test1 = Optional.of(bean1);//抛出异常 java.lang.NullPointerException
  • ofNullable

为指定的值创建一个Optional,如果指定的值为null,则返回一个空的Optional.ofNullable与of方法相似,唯一的区别是可以接受参数为null的情况

TestBean bean = new TestBean(1,"test1",15,1);
Optional test = Optional.ofNullable(bean);
TestBean bean1 = null;
Optional test1 = Optional.ofNullable(bean1);

isPresent

判断Optional对象中的值是否存在,若存在返回true,否则返回false

/**
     * Return {@code true} if there is a value present, otherwise {@code false}.
     *
     * @return {@code true} if there is a value present, otherwise {@code false}
     */
    public boolean isPresent() {
        return value != null;
    }
Optional optional1 = Optional.ofNullable("HelloWordl");
boolean flag = optional1.isPresent();

get

若Optional对象中的值存在则通过get()获取,否则抛NoSuchElementException异常

    /**
     * If a value is present in this {@code Optional}, returns the value,
     * otherwise throws {@code NoSuchElementException}.
     *
     * @return the non-null value held by this {@code Optional}
     * @throws NoSuchElementException if there is no value present
     *
     * @see Optional#isPresent()
     */
    public T get() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }
Optional optional = Optional.ofNullable("HelloWordl");
String str = optional.get();

ifPresent

如果 Optional 中有值,则对该值调用 consumer.accept,否则什么也不做

/**
     * If a value is present, invoke the specified consumer with the value,
     * otherwise do nothing.
     *
     * @param consumer block to be executed if a value is present
     * @throws NullPointerException if value is present and {@code consumer} is
     * null
     */
    public void ifPresent(Consumer consumer) {
        if (value != null)
            consumer.accept(value);
    }
Optional optional = Optional.ofNullable("HelloWordl");
String str = optional.get();
optional.ifPresent(item->System.out.println(item));

orElse

如果 Optional 中有值则将其返回,否则返回 orElse 方法传入的参数

/**
     * Return the value if present, otherwise return {@code other}.
     *
     * @param other the value to be returned if there is no value present, may
     * be null
     * @return the value, if present, otherwise {@code other}
     */
    public T orElse(T other) {
        return value != null ? value : other;
    }
Optional optional = Optional.of("HelloWorld");    
System.out.println(optional.orElse("Java"));
optional = Optional.ofNullable(null);   
System.out.println(optional.orElse("Java"));

orElseGet

orElseGet 与 orElse 方法的区别在于,orElseGet 方法传入的参数为一个 Supplier 接口的实现 —— 当 Optional 中有值的时候,返回值;当 Optional 中没有值的时候,返回从该 Supplier 获得的值。

/**
     * Return the value if present, otherwise invoke {@code other} and return
     * the result of that invocation.
     *
     * @param other a {@code Supplier} whose result is returned if no value
     * is present
     * @return the value if present otherwise the result of {@code other.get()}
     * @throws NullPointerException if value is not present and {@code other} is
     * null
     */
    public T orElseGet(Supplier other) {
        return value != null ? value : other.get();
    }
Optional optional = Optional.of("HelloWorld");
System.out.println(optional.orElseGet(()->"Java"));
optional = Optional.ofNullable(null);  
System.out.println(optional.orElseGet(()->"Java"));

orElseThrow

orElseThrow 与 orElse 方法的区别在于,orElseThrow 方法当 Optional 中有值的时候,返回值;没有值的时候会抛出异常,抛出的异常由传入的 exceptionSupplier 提供

/**
     * Return the contained value, if present, otherwise throw an exception
     * to be created by the provided supplier.
     *
     * @apiNote A method reference to the exception constructor with an empty
     * argument list can be used as the supplier. For example,
     * {@code IllegalStateException::new}
     *
     * @param  Type of the exception to be thrown
     * @param exceptionSupplier The supplier which will return the exception to
     * be thrown
     * @return the present value
     * @throws X if there is no value present
     * @throws NullPointerException if no value is present and
     * {@code exceptionSupplier} is null
     */
    public  T orElseThrow(Supplier exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }
Optional optional = Optional.of("HelloWorld");
System.out.println(optional.orElseThrow(()->new StringNotFoundException("String Not Found")));
optional = Optional.ofNullable(null);
System.out.println(optional.orElseThrow(()->new StringNotFoundException("String Not Found")));

filter

如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional。

Optional optional = Optional.of("HelloWorld");
System.out.println(optional.filter(item->item.length()>10).orElse("NotFoundString"));

map

如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。

Optional optional = Optional.of("HelloWorld");
System.out.println(optional.filter(item->item.length()>=5).map(item->item+"----->").get());

flatMap

如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional。flatMap与map(Funtion)方法类似,区别在于flatMap中的mapper返回值必须是Optional。调用结束时,flatMap不会对结果用Optional封装。

Optional optional = Optional.of("HelloWorld");
System.out.println(optional.filter(item->item.length()>=5).map(item->item+"----->").flatMap(item->Optional.of(item)).get());

你可能感兴趣的:(Java8新特性)