都什么时候了才来学Java8新特性?

145 阅读4分钟

Lamdba表达式

当一个接口只有一个抽象方法,称为函数式接口,这种接口可以以lamdba表达式来实现,目的是为了更简洁的代码

    //1.无参数无返回值
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("hello lamdba");
        }
    };
    Runnable r1 = () -> {System.out.println("hello lamdba");};
    //lamdba只有一条语句,可省大括号
    Runnable r2 = () -> System.out.println("hello lamdba");

    //2.一个参数无返回值
    Consumer<String> consumer = new Consumer<String>() {
        @Override
        public void accept(String s) {
            System.out.println("hello lamdba");
        }
    };
    Consumer<String> consumer1 = (String s) ->System.out.println("hello lamdba");
    //可省参数类型
    Consumer<String> consumer2 = (s) ->System.out.println("hello lamdba");
    //一个参数可省括号
    Consumer<String> consumer3 = s ->System.out.println("hello lamdba");

    //3.多参数有返回值
    Comparator<Integer> comparator = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return Integer.compare(o1, o2);
        }
    };
    //多参数括号不可省,只有一条return语句,可省return
    Comparator<Integer> comparator1 = (o1,o2) -> Integer.compare(o1, o2);

总结 -> 左边:lambda形参的参数类型可以省略,当lambda形参只有一个参数可以省略括号 -> 右边:如果lambda体只有一条执行语句省略{},这条语句是return时省略return

方法引用

方法引用是lamdba表达式的一种更简洁的形式 当满足lambda体只有一条执行语句且 1.函数式接口方法中的抽象方法的形参列表和返回值类型与引用方法的形参列表和返回值类型相同 2.函数式接口方法的第一个参数是需要引用方法的调用者,并且第二个参数是需要引用方法的参数

    //对象::实例方法
    Consumer<String> consumer = s ->System.out.println("hello lamdba");
    PrintStream ps = System.out;
    Consumer<String> consumer1 = ps::print;
    //类::静态方法
    Comparator<Integer> comparator = (o1,o2) -> Integer.compare(o1, o2);
    Comparator<Integer> comparator1 = Integer::compare;
    //类::实例方法
    Comparator<String> comp = (s1,s2) -> s1.compareTo(s2);
    Comparator<String> comp1 = String::compareTo;

    //构造器引用类似方法引用
    Supplier<Test> supplier1 = () -> new Test();
    Supplier<Test> supplier2 = Test::new;
    //数组引用类似方法引用
    Function<Integer, String[]> func = integer -> new String[integer];
    Function<Integer, String[]> func1 = String[]::new;

StreamAPI

Collection关注的是数据的存储,Stream关注的是数据的运算 Java8提供了一套Stream api,使用这套api可以对内存中的数据进行过滤、排序、映射、归约等操作 Stream 自己不会存储元素 Stream 不会改变源对象。相反,他们会返回一个持有结果的新 Stream Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行

创建Stream
    //1.使用集合创建
    List<Integer> list = new ArrayList<>();
    Stream<Integer> stream = list.stream();
    //2.使用数组创建
    Arrays.stream(new int[]{1,2,3});
    //3.使用Stream静态方法
    Stream.of(1,2,3);
中间操作

1.筛选和切片

    //1.1 filter,从流中排除元素
        list.stream().filter(n -> n>=2).forEach(System.out::println);
    //1.2 distinct,从流中去重元素
        list.stream().distinct().forEach(System.out::println);
    //1.3 limit,从流中截断元素
        list.stream().limit(1).forEach(System.out::println);
    //1.4 skip,从流中跳过元素
        list.stream().skip(1).forEach(System.out::println);

2.映射

    //2.1 map,对Integer,String集合,直接对集合的元素做映射
        list.stream().map(n -> n+1).forEach(System.out::println);
    //2.2 flatMap,对集合中又有集合,先对集合中的元素映射为流,再去对流中的元素做操作,最后会将所有的流合并为一个流
        List<List<Integer>> listForMap = Arrays.asList(Arrays.asList(1,2),Arrays.asList(2,3));
        listForMap.stream().flatMap(n -> n.stream()).map(n -> n+1).forEach(System.out::println);

3.排序

    //3.1 sorted,对流中元素排序
        list.stream().sorted().forEach(System.out::println);
    //3.2 sorted(),自定义排序
        list.stream().sorted((x,y) -> Integer.compare(y,x)).forEach(System.out::println);
终止操作

1.匹配和查找

allMatch(),anyMatch(),noneMath(),findFirst(),findAny(),count(),max(),min(),forEach()

2.规约

    //2.1 reduce,累加
    System.out.println(list.stream().reduce(Integer::sum).get());

3.收集

   //3.1 collect,转换流到集合
   List<Integer> collectList = list.stream().filter(n -> n >= 2).collect(Collectors.toList());
   collectList.stream().forEach(System.out::println);

Option类

ofNullable() 和 orElse() 搭配使用,不确定对象非空

    String str ="hello java";
    str = null;
    Optional<String> optional = Optional.ofNullable(str);
    System.out.println(optional);
    //orElse(T t1):如果Optional内部的value非空,则返回此value值。如果value为空,则返回t1.
    String str2 = optional.orElse("hello lamdba");
    System.out.println(str2);

垂直与水平

    Stream.of("a", "b", "c", "d", "e")
            .map(str -> {
                System.out.println("map: \t" + str);
                return str.toUpperCase();
            })
            .filter(str -> {
                System.out.println("filter: " + str);
                return str.equals("c") || str.equals("C");
            })
            .forEach(str -> {
                System.out.println("forEach: " + str);
            });
}
map: 	a
filter: A
map: 	b
filter: B
map: 	c
filter: C
forEach: C
map: 	d
filter: D
map: 	e
filter: E

每一个数据垂直地从map到filter再到forEach,其中map filter各执行了5次,forEach执行了1次。如果我们改变中间操作的顺序,将filter移动到链头的最开始,就可以大大减少实际的执行次数:

Stream.of("a", "b", "c", "d", "e")
        .filter(str -> {
            System.out.println("filter: " + str);
            return str.equals("c") || str.equals("C");
        })
        .map(str -> {
            System.out.println("map: \t" + str);
            return str.toUpperCase();
        })
        .forEach(str -> {
            System.out.println("forEach: " + str);
        });
        filter: a
filter: b
filter: c
map: 	c
forEach: C
filter: d
filter: e

其中filter执行了5次,map forEach执行了1次。

    Stream.of("b", "a", "e", "d", "c")
            .map(str -> {
                System.out.println("map: \t" + str);
                return str.toUpperCase();
            })
            .sorted((str1, str2) -> {
                System.out.println("sorted: " + str1 + ", " + str2);
                return str1.compareTo(str2);
            })
            .filter(str -> {
                System.out.println("filter: " + str);
                return str.equals("c") || str.equals("C");
            })
            .forEach(str -> {
                System.out.println("forEach: " + str);
            });
}
map: 	b
map: 	a
map: 	e
map: 	d
map: 	c
sorted: A, B
sorted: E, A
sorted: E, B
sorted: D, B
sorted: D, E
sorted: C, D
sorted: C, B
filter: A
filter: B
filter: C
forEach: C
filter: D
filter: E

sorted是水平执行的。

提高代码效率的好用技巧

1.使用Collectors.groupingBy进行分组

Map<Long, List<User>> userById = userList.stream() .collect(Collectors.groupingBy(user -> user.getAge));

2.list转map

Map<Long, User> userById = userList.stream().collect(Collectors.toMap(User::getId, user -> JSON.toJSONString(user))));

3.逗号分割的字符串id转换idList,idList转换逗号分割的字符串id

List<Long> idList = Arrays.stream(form.getUserIds.split(",")).map(id -> Long.valueOf(id)).collect(Collectors.toList());

String userIds = idList.stream().map(String::valueOf).collect(Collectors.joining(",");

4.list根据属性去重

userList.stream().collect(Collectors.collectingAndThen(
        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(User::getName))), ArrayList::new))

5.list根据属性排序

userList.stream().sorted(Comparator.comparing(User::getAge,Comparator.reverseOrder())).collect(Collectors.toList())

6.list抽取部分属性转换成新list

List<Person> personList = userList.stream().map(user -> new Person(user.getName(), user.getAge())).collect(Collectors.toList())

7.判断list中是否包含某个属性值

userList.stream().anyMatch(user -> user.getName().equals("Will_Liao")))