Java学习笔记Day16 JDK8新特性 Lambda表达式,Stream API

JDK8新特性

Java8是oracle公司于2014年3月发布,可以看成Java5以来最具革命性的版本。Java8为Java语言,编译器,类库,开发工具于JVM带来了大量新特性。

Lambda表达式

Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁,更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。

格式

->:Lambda操作符 或 箭头操作符

左边:Lambda形参列表(其实就是接口中的抽象方法的形参列表)

右边:Lambda体(其实就是重写的抽象方法的方法体)

六种使用情况

无参无返回值的情况

    @Test
    public void test() {
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("开炮!");
            }
        };
        r1.run();

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

        //Lambda表达式的写法
        Runnable r2 = () -> System.out.println("开跑!");
        r2.run();
    }

需要一个参数,但没有返回值

    @Test
    public void test() {
        Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        consumer.accept("test");

        //Lambda表达式的写法
        Consumer<String> consumer1 = (String s) -> {
            System.out.println(s);
        };
        consumer1.accept("test");
    }

数据类型可省略,因为可以编译器推断得出,称为"类型推断"

        //Lambda表达式的写法
        Consumer<String> consumer1 = (s) -> {
            System.out.println(s);
        };
        consumer1.accept("test");

若只需一个参数,参数的小括号可以省略

        Consumer<String> consumer1 = s -> {
            System.out.println(s);
        };
        consumer1.accept("test");

需要两个或以上的参数,多条执行语句,并且可以有返回值

    @Test
    public void test() {
        Comparator<Integer> comparator = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return o1.compareTo(o2);
            }
        };
        int result = comparator.compare(11, 44);
        System.out.println(result);
        System.out.println("-----------");
        //Lambda表达式的写法
        Comparator<Integer> comparator1 = (o1, o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };
        int result1 = comparator.compare(33, 4);
        System.out.println(result1);
    }

当Lambda体只有一条执行语句时return和大括号都能省

   @Test
    public void test() {
        Comparator<Integer> comparator = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        };
        int result = comparator.compare(11, 44);
        System.out.println(result);
        System.out.println("-----------");
        //Lambda表达式的写法
        Comparator<Integer> comparator1 = (o1, o2) -> o1.compareTo(o2);
        int result1 = comparator.compare(33, 4);
        System.out.println(result1);
    }

Lambda表达式的本质:作为函数式接口的实例

函数式接口

如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口

在接口上加上@FunctionalInterface注解,这样做可以检查它是否是一个函数式接口(同时javadoc也会包含一条声明,说明这个接口是一个函数式接口)

如何理解函数式接口

 Java内置的四大核心函数式接口

 例:

    @Test
    public void test() {
        //消费型
        Consumer<String> consumer = s -> System.out.println(s);
        consumer.accept("我是一个字符串");
        //供给型
        Supplier<Integer> supplier = () -> new Random().nextInt(5) + 1;
        Integer random = supplier.get();
        System.out.println(random);
        //函数型
        Function<String, Integer> function = (s) -> {
            Integer i = Integer.parseInt(s);
            return i;
        };
        Integer integer = function.apply("123");
        System.out.println(integer);
        //断定型
        Predicate<Integer> predicate = i -> i >= 100;
        boolean result = predicate.test(10);
        System.out.println(result);
    }

其他接口

Lambda表达式是可传递的代码的理解

public class LambdaTest {
    @Test
    public void test() {
        //断定型
        Predicate<Integer> predicate = i -> i >= 100;

        //Lambda表达式是可传递的代码的理解
        List<Integer> list = new ArrayList<>(Arrays.asList(15, 88, 1000, 55, 94, 401, 510));
        System.out.println(list);
        filter(list, predicate);
        System.out.println(list);
    }

    //此方法为删除指定列表的大于100的元素
    public List<Integer> filter(List<Integer> list, Predicate<Integer> pre) {
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()) {
            Integer next = iterator.next();
            if (pre.test(next)) {
                iterator.remove();
            }
        }
        return list;
    }
}

方法引用和构造器引用

方法引用

当要传递给Lambda体的操作,已经有了实现的方法了,可以使用方法引用

方法引用可以看做是Lambda表达式深层次的表达,换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。

要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致

格式:使用操作符“::”将类(或对象)与方法名分隔开来。

如下三种主要使用情况:

对象::实例方法

public class MethodRefTest {
    //对象::实例方法
    @Test
    public void test() {
        //例1
        //Lambda表达式写法
        Consumer<String> con1 = s -> System.out.println(s);
        con1.accept("学习使我快乐!");

        //方法引用的写法
        PrintStream ps = System.out;
        Consumer<String> con2 = ps::println;
        con2.accept("也使我十分充实");

        //例2
        //Lambda表达式的写法
        Student student = new Student("GYQ", 12);
        Supplier<String> supplier = () -> student.getName();
        String name = supplier.get();
        System.out.println(name);

        //方法引用的写法
        Supplier<String> supplier1 = student::getName;
        String name1 = supplier1.get();
        System.out.println(name1);
    }
}

class Student {
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }
}

::静态方法

public class MethodRefTest {
    //类::静态方法
    @Test
    public void test() {
        //例1
        //Lambda表达式写法
        Comparator<Double> comparator = (d1, d2) -> Double.compare(d1, d2);
        int result = comparator.compare(55.5, 888.8);
        System.out.println(result);
        //方法引用的写法
        Comparator<Double> comparator1 = Double::compare;
        int result1 = comparator.compare(77.77, 66.66);
        System.out.println(result1);

        //例2
        //Lambda表达式写法
        Function<Double, Long> function = d -> Math.round(d);
        Long round = function.apply(99.9);
        System.out.println(round);
        //方法引用的写法
        Function<Double, Long> function1 = Math::round;
        Long round1 = function1.apply(55.4);
        System.out.println(round1);
    }
}

::实例方法(与前两种不同)

public class MethodRefTest {
    //类::静态方法
    @Test
    public void test() {
//        第一个参数是方法的调用者
        //例1
        //Comparator中的 int compare(T t1,T t2);
        //String中的 int t1.compareTo(t2)
        //Lambda表达式写法
        Comparator<String> comparator = (s1, s2) -> s1.compareTo(s2);
        int result = comparator.compare("asd", "azd");
        System.out.println(result);
        //方法引用的写法
        Comparator<String> comparator1 = String::compareTo;
        int result2 = comparator1.compare("bdx", "bad");
        System.out.println(result2);

        //例2
        //BiPredicate中的boolean test(T t1,T t2);
        //String中的boolean t1.equals(t2);
        //Lambda表达式写法
        BiPredicate<String, String> predicate = (s1, s2) -> s1.equals(s2);
        boolean isEquals = predicate.test("asd", "asd");
        System.out.println(isEquals);
        //方法引用的写法
        BiPredicate<String, String> predicate1 = String::equals;
        boolean isEquals1 = predicate1.test("sss", "ddsa");
        System.out.println(isEquals1);

        //例3
        //Function中的R apply(T t);
        //Student中的String getName();
        //Lambda表达式写法
        Function<Student, String> function = stu -> stu.getName();
        String name = function.apply(new Student("GQY", 15));
        System.out.println(name);
        //方法引用的写法
        Function<Student, String> function1 = Student::getName;
        String name1 = function1.apply(new Student("AAA", 55));
        System.out.println(name1);
    }
}

class Student {
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }
}

构造器引用

与方法引用类似,函数式接口的抽象方法的形参列表与构造器的形参列表一致,抽象方法的返回值即为构造器所属的类的类型

public class ConstructorRefTest {
    //构造器引用
    @Test
    public void test() {
        //例1
        //Lambda表达式写法
        Supplier<Student> supplier = () -> new Student();
        Student student = supplier.get();
        System.out.println(student);
        //构造器引用的写法
        Supplier<Student> supplier1 = Student::new;
        Student student1 = supplier1.get();
        System.out.println(student1);

        //例2
        //Lambda表达式写法
        Function<String, Student> function = s -> new Student(s);
        Student student2 = function.apply("GGG");
        System.out.println(student2);
        //构造器引用的写法
        Function<String, Student> function1 = Student::new;
        Student student3 = function1.apply("AAA");
        System.out.println(student3);

        //例3
        //Lambda表达式写法
        BiFunction<String, Integer, Student> biFunction = (s, i) -> new Student(s, i);
        Student student4 = biFunction.apply("GYQ", 18);
        System.out.println(student4);
        //构造器引用的写法
        BiFunction<String, Integer, Student> biFunction1 = Student::new;
        Student student5 = biFunction1.apply("ZZZ", 10);
        System.out.println(student5);
    }
}

class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name) {
        this.name = name;
    }

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

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

数组引用

将数组看作一个特殊的类,与构造器引用用法一致

    //数组引用
    @Test
    public void test() {
        //例1
        //Lambda表达式写法
        Function<Integer, String[]> function = length -> new String[length];
        String[] arr1 = function.apply(10);
        System.out.println(Arrays.toString(arr1));
        //数组引用的写法
        Function<Integer, String[]> function1 = String[]::new;
        String[] arr2 = function1.apply(10);
        System.out.println(Arrays.toString(arr2));
    }

强大的Stream API 

Stream API把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提高程序员的生产力,让程序员写出高效率,干净,简洁的代码。

Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找,过滤和映射数据等操作。使用Stream API对集合数据进行操作,就类似使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作。简而言之,Stream API提供了一种高效且易于使用的处理数据的方式。

为什么要使用Stream API

实际开发中,项目中多数数据源都来自Mysql,Oracle等。但现在数据源可以更多了,有MangoDB,Redis等,而这些NoSQL的数据就需要Java层面去处理。

Stream和Collection集合的区别:Collection是一种静态的内存数据结构,而Stream是有关计算的。前者是主要面向内存,存储在内存中,后者主要是面向CPU,通过CPU实现计算。

Stream到底是什么?

是数据渠道,用于操作数据源(集合,数组等)所生成的元素序列。

集合讲的是数据,Stream讲的是计算!

注意:

        Stream自己不会存储元素。

        Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。

        Stream操作是延迟执行的,这意味着他们会等到需要结果的时候才执行。

Stream操作的三个步骤

1、创建Stream        一个数据源(如:集合,数组),获取一个流

2、中间操作        一个中间操作链,对数据源的数据进行处理

3、中止操作(终端操作)        一旦执行中止操作,就执行中间操作链,并产生结果,之后,不会再被使用

Stream的实例化

public class StreamTest {
    @Test
    public void test() {
        //创建Stream的方式一:通过集合
        //Collection接口中的默认方法
        List<Student> students = StudentData.getStudentData();
        //返回一个顺序流
        Stream<Student> stream = students.stream();
        //返回一个并行流
        Stream<Student> parallelStream = students.parallelStream();

        //创建Stream方式二:通过Arrays类的静态方法,传入一个泛型数组
        //static <T> Stream<T> stream(T[] array)
        int[] arr = new int[]{1, 2, 3, 4, 5, 6};
        IntStream stream1 = Arrays.stream(arr);

        Student[] students1 = new Student[3];
        students1[0] = new Student("name1", 1);
        students1[1] = new Student("name2", 2);
        students1[2] = new Student("name3", 3);
        Stream<Student> stream2 = Arrays.stream(students1);

        //创建Stream方式三:通过Stream的of()
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6);

        //创建Stream方式四:创建无限流
        //迭代 iterate
        //public static<T> Stream<T> iterate(final T seed,final UnaryOperator<T> f)
        Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);//遍历前10个偶数

        //生成
        //public static<T> Stream<T> generate(Supplier<T> s)
        Stream.generate(Math::random).limit(10).forEach(System.out::println);
    }
}

class StudentData {
    public static List<Student> getStudentData() {
        List<Student> list = new ArrayList<>();
        list.add(new Student("GYQ", 100));
        list.add(new Student("UZI", 990));
        list.add(new Student("CLV", 90));
        list.add(new Student("GDV", 75));
        list.add(new Student("HOB", 95));
        list.add(new Student("DSA", 66));
        return list;
    }
}

class Student {
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }
}

并行流和串行流

并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。相比较串行的流,并行的流可以很大程度上提高程序的指定效率。

Java8中将并行进行了优化,我们可以很容易的对数据进行并行操作。StreamAPI可以声明性的通过parallel()与sequential()在并行与顺序流之间进行切换。

注意:

使用并行流并不是一定会提高效率,因为jvm对数据进行切片和切换线程也是需要时间的。所以数据量越小,串行操作越快;数据量越大,并行操作效果越好。

//并行流和串行流
    @Test
    public void test() {
        //测试串行流速度
        long start = System.currentTimeMillis();
        OptionalLong sum = LongStream.rangeClosed(0, 100000000).sequential().reduce(Long::sum);
        System.out.println(sum.getAsLong());
        long end = System.currentTimeMillis();
        System.out.println("串行流" + (end - start) + "ms");

        //测试并行流速度
        start = System.currentTimeMillis();
        OptionalLong sum1 = LongStream.rangeClosed(0, 100000000).parallel().reduce(Long::sum);
        System.out.println(sum1.getAsLong());
        end = System.currentTimeMillis();
        System.out.println("并行流" + (end - start) + "ms");
    }

Stream的中间操作

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何处理!而在中止操作时一次性全部处理,称为”惰性求值“。

筛选与切片

public class StreamTest {
    //筛选与切片
    @Test
    public void test() {
        //filter(Predicate p) 接收Lambda,从流中排除某些元素
        List<Student> list = StudentData.getStudentData();
        Stream<Student> stream = list.stream();
        //查询集合中年龄小于100的
        stream.filter(stu -> stu.getAge() < 100).forEach(System.out::println);
        System.out.println("-------------------");

        //limit(n) 截断流,使其元素不超过给定数量
        Stream<Student> stream1 = list.stream();//不能使用上面已经终止的stream
        //查询集合中前四个元素
        stream1.limit(4).forEach(System.out::println);
        System.out.println("-------------------");

        //skip(n) 跳过元素,返回一个跳过前n个元素的流,若流中元素不足n个则返回一个空流
        list.stream().skip(2).forEach(System.out::println);
        System.out.println("-------------------");

        //distinct() 筛选,通过流所生成元素的hashCode()和equals()去除重复元素
        list.stream().distinct().forEach(System.out::println);
    }
}

class StudentData {
    public static List<Student> getStudentData() {
        List<Student> list = new ArrayList<>();
        list.add(new Student("GYQ", 100));
        list.add(new Student("UZI", 990));
        list.add(new Student("UZI", 990));
        list.add(new Student("CLV", 90));
        list.add(new Student("GDV", 75));
        list.add(new Student("HOB", 95));
        list.add(new Student("DSA", 66));
        return list;
    }
}

class Student {
    private String name;
    private int age;

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


    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

映射

public class StreamTest {
    //映射
    @Test
    public void test() {
        //map(Function f) 接收一个函数作为参数,将元素转换为其他形式或提取信息
        //该函数会被应用到每一个元素上,并将其映射为一个新的元素
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd", "ff");
        list.stream().map(s -> s.toUpperCase()).forEach(System.out::println);
        System.out.println("----------------");
        //练习1:获取学生年龄大于99的学生的年龄
        List<Student> studentData = StudentData.getStudentData();
        Stream<Student> stream = studentData.stream();
        Stream<Integer> agesStream = stream.map(Student::getAge);
        agesStream.filter(s -> s > 99).forEach(System.out::println);
        System.out.println("----------------");

        //练习2:
        Stream<Stream<Character>> streamStream = list.stream().map(StreamTest::fromStringToStream);
        streamStream.forEach(s -> s.forEach(System.out::println));
        System.out.println("----------------");

        //flapMap(Function f) 接收一个函数作为参数,将流中的每一个值都换成另一个流,然后把所有流连接成一个流
        //flap:展平 下方例子和上面对比着看,类似于add(T[])和addAll(T[])的差异
        Stream<Character> characterStream = list.stream().flatMap(StreamTest::fromStringToStream);
        characterStream.forEach(System.out::println);
    }

    public static Stream<Character> fromStringToStream(String str) {
        ArrayList<Character> list = new ArrayList<>();
        for (Character c : str.toCharArray()) {
            list.add(c);
        }
        return list.stream();
    }
}

class StudentData {
    public static List<Student> getStudentData() {
        List<Student> list = new ArrayList<>();
        list.add(new Student("GYQ", 100));
        list.add(new Student("UZI", 990));
        list.add(new Student("UZI", 990));
        list.add(new Student("CLV", 90));
        list.add(new Student("GDV", 75));
        list.add(new Student("HOB", 95));
        list.add(new Student("DSA", 66));
        return list;
    }
}

排序

public class StreamTest {
    //排序
    @Test
    public void test() {
        List<Student> list = StudentData.getStudentData();
        //sorted() 自然排序 需要集合元素实现Comparable接口
        //根据集合内元素实现Comparable接口并重写compareTo()时指定的排序规则排序
        Stream<Student> stream = list.stream();
        stream.sorted().forEach(System.out::println);
        System.out.println("------------");

        //sorted(Comparator) 定制排序 此例为根据年龄排
        list.stream().sorted((s1, s2) -> Integer.compare(s1.getAge(), s2.getAge())).forEach(System.out::println);
    }
}

class StudentData {
    public static List<Student> getStudentData() {
        List<Student> list = new ArrayList<>();
        list.add(new Student("GYQ", 100));
        list.add(new Student("UZI", 990));
        list.add(new Student("UZI", 991));
        list.add(new Student("CLV", 90));
        list.add(new Student("GDV", 75));
        list.add(new Student("HOB", 95));
        list.add(new Student("DSA", 66));
        return list;
    }
}

//实现自然排序,先按照姓名排,姓名相同则按照年龄由大到小
class Student implements Comparable {
    private String name;
    private int age;

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


    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    @Override
    public int compareTo(Object o) {
        if (o instanceof Student) {
            Student student = (Student) o;
            if (this.getName().compareTo(((Student) o).getName()) == 0) {
                return Integer.compare(this.getAge(), student.getAge());
            } else
                return this.getName().compareTo((student.getName()));
        } else
            throw new RuntimeException("类型错误!");
    }
}

Stream的终止操作

终端操作会从流的流水线生成结果,其结果可以是任何不是流的值,例如:List,Integer,甚至是void。

流进行了终止操作后,不能再次使用。

匹配与查找

public class StreamAPITest {
    //匹配与查找
    @Test
    public void test() {
        List<Student> list = StudentData.getStudentData();
        //allMatch(Predicate p)  检查是否匹配所有元素
        boolean isAllMatch = list.stream().allMatch(s -> s.getAge() > 100);
        System.out.println(isAllMatch);
        //anyMatch(Predicate p)  检查是否匹配至少一个元素
        boolean isAnyMatch = list.stream().anyMatch(s -> "GYQ".equals(s.getName()));
        System.out.println(isAnyMatch);
        //noneMatch(Predicate p)  检查是否没有匹配的元素
        boolean isNoneMatch = list.stream().noneMatch(s -> s.getName().startsWith("G"));
        System.out.println(isNoneMatch);
        //findFirst  返回第一个元素
        Optional<Student> firstStudent = list.stream().findFirst();
        System.out.println(firstStudent);
        //findAny  返回当前流中任意元素 串行流一般返回第一个元素,并行流就不确定
        Optional<Student> anyStudent = list.parallelStream().findAny();
        System.out.println(anyStudent);
        //count  返回流中元素的总个数
        long changshoucount = list.stream().filter(s -> s.getAge() > 100).count();
        System.out.println(changshoucount);
        //max(Comparator c)  返回流中最大值
        Optional<Integer> maxAge = list.stream().map(s -> s.getAge()).max(Integer::compare);
        System.out.println(maxAge);
        //min(Comparator c)  返回流中最小值
        //返回流中年纪最小的学生
        Optional<Student> youngestStudent = list.stream().min((s1, s2) -> Integer.compare(s1.getAge(), s2.getAge()));
        System.out.println(youngestStudent);
        //forEach  内部迭代
        list.stream().forEach(System.out::println);
    }
}

class StudentData {
    public static List<Student> getStudentData() {
        List<Student> list = new ArrayList<>();
        list.add(new Student("GYQ", 100));
        list.add(new Student("UZI", 990));
        list.add(new Student("UZI", 991));
        list.add(new Student("CLV", 90));
        list.add(new Student("GDV", 75));
        list.add(new Student("HOB", 95));
        list.add(new Student("DSA", 66));
        return list;
    }

归约

    //归约
    @Test
    public void test() {
        //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);
        //计算所有student的年龄和
        //reduce(BinaryOperator) 将流中元素反复结合起来,得到一个值,返回Optional<T>
        Stream<Student> stream = StudentData.getStudentData().stream();
        Stream<Integer> ageStream = stream.map(Student::getAge);
        Optional<Integer> sumOfAge = ageStream.reduce(Integer::sum);
        System.out.println(sumOfAge);
    }

收集

    collect(Collector c) 将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
    Collector接口中的方法的实现决定了如何对流执行收集的操作(如收集到的List,Set,Map)
    另外Collectors实用类提供了很多静态方法,可以方便的创建常用收集器的实例,具体方法见图

    //收集
    @Test
    public void test() {
        //collect(Collector c) 将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
        //练习1 将年龄大于99的学生放入一个List或Set
        List<Student> list = StudentData.getStudentData();
        Stream<Student> stream = list.stream();
        List<Student> studentList = stream.filter(s -> s.getAge() > 99).collect(Collectors.toList());
        studentList.forEach(System.out::println);
        System.out.println("----------------");

        //set
        Set<Student> studentSet = list.stream().filter(s -> s.getAge() > 99).collect(Collectors.toSet());
        studentSet.forEach(System.out::println);
    }

Optionnal类

方法

 

Optional类用法

实例化

    @Test
    public void test() {
        //Optional.of(T t)  创建Optional实例,t必须非空
        Student student = new Student();
        //student=null;
        Optional<Student> optionalStudent = Optional.of(student);
        System.out.println(optionalStudent);

        //创建一个空的Optional实例
        Optional<Object> optionalempty = Optional.empty();
        System.out.println(optionalempty);

        //Optional.ofNullable(T t) t可以是空的
        student = null;
        Optional<Student> optionalStudent1 = Optional.ofNullable(student);
        System.out.println(optionalStudent1);
    }

使用

public class OptionalTest {
    @Test
    public void test() {
        //会出现空指针的情况
//        Boy boy = new Boy();
//        String girlName = getGirlName(boy);

        //优化之后
        Boy boy = new Boy();
        String girlName1 = getGirlName1(boy);
        System.out.println(girlName1);

        //使用Optional类
        boy = null;
        String girlName2 = getGirlName2(boy);
        boy = new Boy();
        String girlName3 = getGirlName2(boy);
        boy = new Boy(new Girl("private"));
        String girlName4 = getGirlName2(boy);
        System.out.println(girlName2);
        System.out.println(girlName3);
        System.out.println(girlName4);
    }

    //会出现空指针的情况
    public String getGirlName(Boy boy) {
        return boy.getGirl().getName();
    }

    //优化之后的getGirlName方法
    public String getGirlName1(Boy boy) {
        if (boy != null) {
            Girl girl = boy.getGirl();
            if (girl != null)
                return girl.getName();
        }
        return null;
    }

    //使用Optional类的getGirlName方法
    public String getGirlName2(Boy boy) {
        Optional<Boy> boyOptional = Optional.ofNullable(boy);
        Boy boy1 = boyOptional.orElse(new Boy(new Girl("bus1")));
        Girl girl = boy1.getGirl();
        Optional<Girl> girlOptional = Optional.ofNullable(girl);
        Girl girl1 = girlOptional.orElse(new Girl("bus2"));
        return girl1.getName();
    }
}

class Boy {
    private Girl girl;

    public Boy() {
    }

    public Boy(Girl girl) {
        this.girl = girl;
    }

    public Girl getGirl() {
        return girl;
    }

    public void setGirl(Girl girl) {
        this.girl = girl;
    }

    @Override
    public String toString() {
        return "Boy{" +
                "girl=" + girl +
                '}';
    }
}

class Girl {
    private String name;

    public Girl() {
    }

    public Girl(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Girl{" +
                "name='" + name + '\'' +
                '}';
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值