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<Integer> 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<Integer>() {
            @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<Integer,Integer> customer;
      private BiFunction<Integer,Integer,Integer> function;
      
      public AddNewInterface(BiFunction<Integer,Integer,Integer> function){
          this.function =function;
      }

      public AddNewInterface(BiConsumer<Integer,Integer> 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<Integer,Integer>(){

            @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<Integer,Integer,Integer>(){

            @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<String>() {
            @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<MethodReferenceBean> list = new ArrayList<>();
        for(int i = 0;i<10;i++){
            list.add(new MethodReferenceBean());
        }
        list.forEach(new Consumer<MethodReferenceBean>(){

            @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<Test2> supplier){
        return supplier.get();
    }
    
    public static Test2 newInstance(){
        return new Test2();
    }
}
  • 下一步优化
public class InstanceFactory<T> {

    public  static<T> T getInstance(Supplier<T> 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> {
    
    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<Test2> 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<Student> getDataSource() {
        List<Student> 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<Student> dataSource = getDataSource();
        List<Student> newData = new ArrayList();
        for (Student student : dataSource) {
            if (student.age >= 20 && student.sex == 1) {
                newData.add(student);
            }
        }
        Collections.sort(newData, new Comparator<Student>() {

            @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<Student> 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<E> stream() {
        return StreamSupport.stream(this.spliterator(), false);
    }
//获取并形流
default Stream<E> parallelStream() {
        return StreamSupport.stream(this.spliterator(), true);
    }

例如

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

例如:

String[] names = {"chaimm","peter","john"};
Stream<String> stream = Arrays.stream(names);  
  • 值 直接将几个值变成流对象
Stream<String> 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 <T> the type of stream elements
     * @param s the {@code Supplier} of generated elements
     * @return a new infinite sequential unordered {@code Stream}
     */
    public static<T> Stream<T> generate(Supplier<T> 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.
     *
     * <p>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 <T> 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<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {
        Objects.requireNonNull(f);
        final Iterator<T> iterator = new Iterator<T>() {
            @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 <T> 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 <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
        Objects.requireNonNull(a);
        Objects.requireNonNull(b);

        @SuppressWarnings("unchecked")
        Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
                (Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
        Stream<T> 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.
     *
     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
     * operation</a>.
     *
     * @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.
     *
     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
     * operation</a>.
     *
     * @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<Integer> 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<T>

toSet

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

Set<Integer> 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<T>

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<Integer>()));
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<T>

Optional<Integer> 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<T>

Optional<Integer> 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<T>

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<K,List<T>>

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

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

Map<Boolean,List<Student>> 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<Student> 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<TestBean> test = Optional.of(bean);
TestBean bean1 = null;
Optional<TestBean> test1 = Optional.of(bean1);//抛出异常 java.lang.NullPointerException
  • ofNullable

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

TestBean bean = new TestBean(1,"test1",15,1);
Optional<TestBean> test = Optional.ofNullable(bean);
TestBean bean1 = null;
Optional<TestBean> 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<String> 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<String> 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<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }
Optional<String> 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<String> 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<? extends T> other) {
        return value != null ? value : other.get();
    }
Optional<String> 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 <X> 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 <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }
Optional<String> 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<String> optional = Optional.of("HelloWorld");
System.out.println(optional.filter(item->item.length()>10).orElse("NotFoundString"));

map

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

Optional<String> 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<String> optional = Optional.of("HelloWorld");
System.out.println(optional.filter(item->item.length()>=5).map(item->item+"----->").flatMap(item->Optional.of(item)).get());
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容

  • 原创文章&经验总结&从校招到A厂一路阳光一路沧桑 详情请戳www.codercc.com 对于Java开发者来说,...
    你听___阅读 2,339评论 4 38
  • Java 8自Java 5(发行于2004)以来最具革命性的版本。Java 8 为Java语言、编译器、类库、开发...
    谁在烽烟彼岸阅读 887评论 0 4
  • Java 8自Java 5(发行于2004)以来最具革命性的版本。Java 8 为Java语言、编译器、类库、开发...
    huoyl0410阅读 620评论 1 2
  • 第一天 加油✌✌✌
    馋大喵爱吃鱼阅读 165评论 1 0
  • 午后的阳光,静静地洒落,江边的风暖暖的,一个穿着亚麻色高领毛衣,搭配灰色阔腿裤的年轻女孩,手上拎着一个小方型的暗红...
    雪之梦_325e阅读 319评论 0 2