Java基础-Java8新特性

1. Lambda表达式

  • Lambda是一个匿名函数,可以把Lanbda表达式理解为一段可以传递的代码
import org.junit.Test;

import java.util.Comparator;

/**
 * @author gai
 * @create 2021--02--03
 */
//Lambda表达式的使用举例
public class LambdaTest {


    @Test
    public void test1() {
        Runnable r1 = new Runnable() {

            @Override
            public void run() {
                System.out.println("我爱中国");
            }
        };
        r1.run();
        System.out.println("**************");

        Runnable r2 = () -> System.out.println("我爱中国");
        r2.run();

        Comparator<Integer> com1 = new Comparator<>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1, o2);
            }
        };
        System.out.println(com1.compare(12, 21));

        //Lambda表达式
        Comparator<Integer> com2 = (o1, o2) -> Integer.compare(o1, o2);
        System.out.println(com2.compare(22, 21));

        //方法引用
        Comparator<Integer> com3 = Integer::compare;
        System.out.println(com2.compare(22, 21));
    }
}

/*
(o1,o2)->Integer.compare(o1,o2)
->:lambda操作符
左边:lambda形参列表,就是接口中的抽象方法的形参列表
右边:lambda体,就是重写的抽象方法的方法体
本质还是作为接口的实例
总结:->左边:形参列表的参数类型可以省略(类型推断);如果形参列表只有一个参数,()可以省略
右边:lambda应该使用{}包裹,如果只有一条执行语句可以省略{}、return

Lambda表达式的使用
*/
public class LambdaTest1 {
    //语法格式1:无参,无返回值
    @Test
    public void test1() {
        Runnable r1 = new Runnable() {

            @Override
            public void run() {
                System.out.println("我爱中国");
            }
        };
        r1.run();
        System.out.println("**************");

        Runnable r2 = () -> {
            System.out.println("我爱中国");
        };
        r2.run();
    }

    //语法格式2:需要一个参数,但是没有返回值
    @Test
    public void test2() {
        Consumer<String> con = new Consumer<>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con.accept("我爱中国");
        System.out.println("*************");

        Consumer<String> con1 = (String s) -> {
            System.out.println(s);
        };
        con1.accept("我爱中国");
    }

    //语法格式3:数据类型可以省略,可以由编译器推断得出,“类型推断”
    @Test
    public void test3() {
        Consumer<String> con1 = (s) -> {
            System.out.println(s);
        };
        con1.accept("我爱中国");
    }

    //语法格式4:若只需要一个参数,参数的括号可以省略
    @Test
    public void test4() {
        Consumer<String> con1 = s -> {
            System.out.println(s);
        };
        con1.accept("我爱中国");
    }

    //语法格式5:需要两个以上参数,多条执行语句,并且有返回值
    @Test
    public void test5() {
        Comparator<Integer> com1 = new Comparator<>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return o1.compareTo(o2);
            }
        };

        System.out.println("***************");
        Comparator<Integer> com2 = (o1, o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };
    }

    //语法格式6:当lambda体只有一条语句时,retrun与大括号都可以省略
    @Test
    public void test6() {
        Comparator<Integer> com1 = (o1, o2) -> {
            return o1.compareTo(o2);
        };
        Comparator<Integer> com2 = (o1, o2) -> o1.compareTo(o2);

    }
}

2. 函数式(Functional)接口

  • 如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口
  • 在java.util.function包中定义了Java 8的丰富的函数式接口
  • 以前用匿名实现类表示的现在都可以用Lambda表达式来写
@FunctionalInterface
public interface MyInterface {
    void method();
}

函数式接口
函数式接口

/*java内置的4大核心函数式接口
 * 消费型接口Consumer<T>    void accept(T t)
 * 供给型接口Supplier<T>    T get()
 * 函数型接口Function<T,R>  R apply (T t)
 * 断定型接口Predicate<T>   boolean test(T t)
 * */

public class LambdaTest2 {
    @Test
    public void test1() {
        happyTime(500, new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("价格为" + aDouble);
            }
        });

        happyTime(400, money -> System.out.println("价格为" + money));
    }

    public void happyTime(double money, Consumer<Double> con) {
        con.accept(money);
    }

    @Test
    public void test2() {
        List<String> list = Arrays.asList("北京", "东京", "天津");
        List<String> str = filterString(list, new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.contains("京");
            }
        });
        System.out.println(str);

        List<String> string = filterString(list, s -> s.contains("天"));
        System.out.println(string);
    }

    //根据给定的规则,过滤集合中的字符串。此规则由Predicate的方法决定
    public List<String> filterString(List<String> list, Predicate<String> pre) {
        ArrayList<String> filterList = new ArrayList<>();
        for (String s : list) {
            if (pre.test(s)) {
                filterList.add(s);
            }
        }
        return filterList;
    }
}

3. 方法引用与构造器引用

  • 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用(Method References)
  • 实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法参数列表和返回值类型保持一致
  • 对象::实例方法名 类::静态方法名 类::实例方法名
//方法引用举例
public class MethodRefTest {
    //情况1?:对象::实例方法
    @Test
    public void test1() {
        Consumer<String> con1 = str -> System.out.println(str);
        con1.accept("北京");
        System.out.println("******");

        Consumer<String> con2 = System.out::println;
        con2.accept("上海");
    }

    //情况2:类::静态方法
    @Test
    public void test2() {
        Comparator<Integer> com1 = (t1, t2) -> Integer.compare(t1, t2);
        System.out.println(com1.compare(12, 21));

        Comparator<Integer> com2 = Integer::compare;
        System.out.println(com2.compare(12, 21));

        Function<Double, Long> func1 = d -> Math.round(d);
        Function<Double, Long> func2 = Math::round;
    }

    //情况3:类::实例方法
    @Test
    public void test3() {
        Comparator<String> com1 = (s1, s2) -> s1.compareTo(s2);

        Comparator<String> com2 = String::compareTo;
    }
}
  • 构造器引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致
//数组引用
    @Test
    public void test1() {
        Function<Integer, String[]> function = length -> new String[length];
        String[] arr1 = function.apply(5);
        System.out.println(Arrays.toString(arr1));

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

4. 强大的Stream API

  • Stream API(java.util.stream)把真正的函数式编程引入到Java中,极大提供Java的生产力
  • 使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询,也可以使用Stream API来并行执行操作,提供了一种高效易于使用的处理数据的方式
  • Stream自己不存储元素,不会改变源对象

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

/*
 * Stream执行流程
 * 1.Stream的实例化
 * 2.一系列的中间操作(筛选与切片,映射,排序)
 * 3.终止操作:只有执行终止操作,才执行中间操作。
 * */
public class StreamAPITest {
    @Test
    public void test1() {
        //创建Stream方式1:通过集合
        //default Stream<E> stream():返回一个顺序流
        //default Stream<E> parallelStream():返回一个并行流

        //创建Stream方式2:通过数组
        int[] arr = new int[]{1, 2, 3, 4, 5, 6};
        //调用Arrays类的static <T> Stream<T> stream(T[] array):返回一个流
        IntStream stream = Arrays.stream(arr);

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

        //创建Stream方式4:创建无限流
        //迭代
        Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
        //生成
        Stream.generate(Math::random).limit(10).forEach(System.out::println);
    }
}
//Stream的中间操作
public class StreamAPITest1 {

    //1.筛选与切片
    @Test
    public void test1() {
        int[] arr = new int[]{1, 1, 2, 3, 4, 5, 6};
        IntStream stream = Arrays.stream(arr);
        //filter(Predicate p)接受Lambda,从流中排除某些元素
        //stream.filter().forEach(System.out::println);

        //limit(n)截断流,使其元素不超过给定数量
        //stream.limit(3).forEach(System.out::println);

        //skip(n)跳过元素
        //stream.skip(30).forEach(System.out::println);

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

    //2.映射
    @Test
    public void test2() {
        //map(Function f)
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
        list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);

        //flatMap(Function f)
        Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest1::fromStringToStream);
        streamStream.forEach(s -> {
            s.forEach(System.out::println);
        });

        Stream<Character> characterStream = list.stream().flatMap(StreamAPITest1::fromStringToStream);
        characterStream.forEach(System.out::println);
    }


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

    //3.排序
    @Test
    public void test3() {
        //sorted()自然排序
        List<Integer> list = Arrays.asList(12, 235, 8796, 13, 7964, 44);
        list.stream().sorted().forEach(System.out::println);

        //sorted(Comparator com)定制排序
        list.stream().sorted((o1, o2) -> 0).forEach(System.out::println);
    }
}
//Stream的终止操作
public class StreamAPITest2 {
    //1-匹配与查找
    @Test
    public void test1() {
        //allMatch(Predicate p)检查是否匹配所有元素

        //anyMatch(Predicate p)检查是否至少匹配一个元素

        //noneMatch(Predicate p)检查是否没有匹配的元素

        //findFirst返回第一个元素

        //findAny 返回当前流中的任意元素
        //count返回流中元素的个数
        //max(Comparator c) 返回流中最大值
        //min(Comparator c)返回流中最小值

        //forEach(Consumer c)内部迭代
    }

    //2-归约
    @Test
    public void test2() {
        //reduce(T identity,BinaryOperator)
        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);
    }

    //3-收集
    @Test
    public void test3(){
        //Collet(Collector c)将流转换为其他形式

    }
}

5. Optional类

  • 空指针异常是导致Java应用程序失败的最大原因,为了解决空指针异常,Optional类成为了Java8类库的一部分
  • Optional< T>类(java.util.Optional)是一个容器类,可以保存类型T的值,代表这个值存在。或仅仅保存null,表示这个值不存在,原来用null表示一个值不存在,现在Optional可以更好的表达这个概念,并且可以避免空指针异常
public class OptionalTest {
    @Test
    public void test1() {
        //Optional.of(T t)创建一个Optional实例,t必须非空
        //Optional.empty()创建一个空的Optional实例
        //Optional.ofNullable(T t) t可以为null

        Girl girl = new Girl();
        //girl = null;
        Optional<Girl> optionalGirl = Optional.of(girl);
        Optional<Girl> optionalGirl1 = Optional.ofNullable(girl);

        //orElse(T t1) 如果当前的Optional 内部封装的t是非空的,则返回内部的t;不如果内部t是空的,则返回t1
        Girl girl1 = optionalGirl1.orElse(new Girl("SSS"));
        System.out.println(girl1);
        System.out.println(optionalGirl1);
    }

    public String getGirlName(Boy boy) {
        //原来的写法
        //return boy.getGirl().getName();
        //优化后的
        Optional<Boy> boyOptional = Optional.ofNullable(boy);
        Boy boy1 = boyOptional.orElse(new Boy(new Girl("迪丽热巴")));
        Girl girl = boy1.getGirl();
        Optional<Girl> optional = Optional.ofNullable(girl);
        Girl girl1 = optional.orElse(new Girl("古力娜扎"));
        return girl1.getName();
    }

    @Test
    public void test2() {
        Boy boy = new Boy(new Girl("苍"));
        String girlName = getGirlName(boy);
        System.out.println(girlName);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值