Bootstrap

软件设计之Java入门视频(22)

软件设计之Java入门视频(22)

视频教程来自B站尚硅谷:

尚硅谷Java入门视频教程,宋红康java基础视频
相关文件资料(百度网盘)
提取密码:8op3
idea 下载可以关注 软件管家 公众号

学习内容:

该视频共分为1-717部分
本次内容涉及 660-717(后续Java9、10、11新特性就不一一赘述)
在写代码时,总是需要来回切换界面来看代码要求,这里推荐Snipaste,可以把截图以窗口形式放在屏幕上
记录内容:

  1. 静态代理
  2. 动态代理
  3. Lambda表达式
  4. 函数式接口
  5. 方法引用
  6. Stream API

1、静态代理

interface  ClothFactory{
    void produceCloth();
}
//代理类
class  ProxyClothFactory implements ClothFactory{

    private ClothFactory factory;//用被代理对象进行实例化

    public ProxyClothFactory(ClothFactory factory) {
        this.factory = factory;
    }

    @Override
    public void produceCloth() {
        System.out.println("代理工厂做准备工作");
        factory.produceCloth();
        System.out.println("代理工厂做后续工作");
    }
}
//被代理类
class NikeClothFactory implements ClothFactory{

    @Override
    public void produceCloth() {
        System.out.println("Nike工厂生产运动服");
    }
}
public class StaticProxyTest {
    public static void main(String[] args) {
        //创建被代理类对象
        NikeClothFactory ncf = new NikeClothFactory();
        //创建代理类对象
        ProxyClothFactory pcf = new ProxyClothFactory(ncf);

        pcf.produceCloth();
        //代理工厂做准备工作
        //Nike工厂生产运动服
        //代理工厂做后续工作
    }
}

2、动态代理

interface Human{
    String getBelief();
    void eat(String food);

}
//被代理类
class SuperMan implements Human{

    @Override
    public String getBelief() {
        return "I believe";
    }

    @Override
    public void eat(String food) {
        System.out.println("我喜欢吃" + food);
    }
}
/*
* 想要实现动态代理,需要解决的问题
* 问题1:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象
* 问题2:当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同名方法*/
class  ProxyFactory{
    //调用此方法,返回一个代理类的对象,解决问题1
    public static Object getProxyInstance(Object obj){//obj:被代理类的对象
        MyInvocationHandler handler =  new MyInvocationHandler();
        handler.bind(obj);
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),handler);
    }
}
class MyInvocationHandler implements InvocationHandler{

    private Object obj;//需要使用被代理类对象进行幅值
    public void bind(Object obj){
        this.obj = obj;
    }
    //通过代理类的对象,调用方法a时,会自动调用如下方法:invoke()
    //将被代理类要执行的方法a的功能声明在invoke()中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
        //obj:被代理类对象
        Object returnValue = method.invoke(obj, args);
        return returnValue;
    }
}
public class ProxyTest {
    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();
        //proxyInstance代理类的对象
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
        proxyInstance.eat("四川麻辣");//我喜欢吃四川麻辣
    }
}

3、Lambda表达式

public class LambdaTest {
    //语法格式一:无参,无返回值
    @Test
    public void test(){
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("输出");
            }
        };
        r1.run();

        System.out.println("***********");
        Runnable r2 = () -> {System.out.println("输出2");};
        r2.run();
    }
    @Test
    //语法格式二:Lambda 需要一个参数,但是没有返回值。
    public void test1(){
        Consumer<String> con = new Consumer<String>(){
            @Override
            public void accept(String s){
                System.out.println(s);
            }
        };
        con.accept("你好");
        System.out.println("********");
        Consumer<String> con1 = (String s) -> {System.out.println(s);};
    }
    @Test
    //语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
    public void test3(){
        Consumer<String> con = new Consumer<String>(){
            @Override
            public void accept(String s){
                System.out.println(s);
            }
        };
        con.accept("你好");
        System.out.println("********");
        Consumer<String> con1 = (s) -> {System.out.println(s);};
    }
    @Test
    //语法格式四:Lambda 若只需要一个参数时,参数的小括号可以省略
    public void test4(){
        Consumer<String> con = new Consumer<String>(){
            @Override
            public void accept(String s){
                System.out.println(s);
            }
        };
        con.accept("你好");
        System.out.println("********");
        Consumer<String> con1 = s -> {System.out.println(s);};
    }
    @Test
    //语法格式五:Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值
    public void test5(){
        Comparator<Integer> com1 = new Comparator<Integer>() {
            @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);
        };
        System.out.println(com2.compare(12,6));
    }
    @Test
    //语法格式六:当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略
    public void test6(){
        Comparator<Integer> com1 = (o1,o2) -> o1.compareTo(o2);;
        System.out.println(com1.compare(12,6));
    }
}

4、函数式接口

在这里插入图片描述

5、方法引用

使用情景:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用
方法引用本身上就是Lamda表达式,即也是函数式接口的实例
具体分为三种情况
1) 对象 :: 非静态方法
2)类::静态方法
3)类::非静态方法


public class LambdaTest {
    //情况一: 对象::实例方法
    //Consumer中的void accept(T t)
    //PrintStream中的void println(T t)
    @Test
    public void test(){
       Consumer<String> con1 = str -> System.out.println(str);
       con1.accept("北京");

        System.out.println("**********");
        PrintStream ps = System.out;
        Consumer<String> con2 = ps::println;
        con2.accept("beijing");
    }
    //
    @Test
    //情况二: 类::静态方法
    //Comparator 中的int compare(T t1, T t2)
    //Integer 中的int compare(T t1, T t2)
    public void test1(){
        Comparator<Integer> com1 = (t1,t2) -> Integer.compare(t1,t2);
        System.out.println(com1.compare(12,13));
        Comparator<Integer> com2 = Integer ::compare;
        System.out.println(com2.compare(12,13));
    }
    @Test
    //情况三: 类::实例方法
    //Comparator中的int compare(T t1,T t2)
    //String 中的int t1.compareTo(t2)
    public void test3(){
        Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);
        System.out.println(com1.compare("abc","def"));
        System.out.println("*********");

        Comparator<String> com2 = String ::compareTo;
        System.out.println(com2.compare("abc","def"));
    }

}

6、Stream API

1、Stream关注的是对数据的运算,与CPU打交道
2、集合关注的是数据的存储,与内存打交道
3、注意点
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

在这里插入图片描述

创建Stream

public class StreamAPITest {
    //创建Stream方式一:通过集合
    @Test
    public void test1(){
        List<Employee> employees = EmployeeData.getEmployees();

        //default Stream<E> stream():返回一个顺序流
        Stream<Employee> stream = employees.stream();
        //default Stream<E> parallelStream():返回一个并行流
        Stream<Employee> employeeStream = employees.parallelStream();
    }
    //创建Stream方式二:通过数组
    @Test
    public void test2(){
        int[] arr = new int[]{1,2,3};
        // 调用Arrays类的static <T> Stream<T> stream(T[] array): 返回一个流
        IntStream stream = Arrays.stream(arr);
        Employee e1 = new Employee(1001,"Tom");
        Employee e2 = new Employee(1002,"Jerry");
        Employee[] arr1 = new Employee[]{e1,e2};
        Stream<Employee> stream1 = Arrays.stream(arr1);
    }
    //创建 Stream方式三:通过Stream的of()
    @Test
    public void test3(){
        Stream<Integer> stream = Stream.of(1,2,3);
    }
}

中间操作:筛选

public class StreamAPITest {
    //创建Stream方式一:通过集合
    @Test
    public void test1() {
        List<Employee> list = EmployeeData.getEmployees();
        //filter(Predicate p)——接收Lambda,从流中排除某些元素
        Stream<Employee>stream = list.stream();
        stream.filter(e -> e.getSalary() > 7000).forEach(System.out ::println);
        System.out.println();

        //limit(long maxSize) 截断流,使其元素不超过给定数量
        list.stream().limit(3).forEach(System.out ::println);
        System.out.println();
        //skip(long n)
        //跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流与 limit(n) 互补
        list.stream().skip(3).forEach(System.out ::println);

        //distinct() 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
        list.add(new Employee(1010,"刘强东",40,8000));
        list.add(new Employee(1010,"刘强东",40,8000));
        list.add(new Employee(1010,"刘强东",40,8000));
        list.stream().distinct().forEach(System.out ::println);
    }

中间操作:映射

 @Test
    public void test2() {
//        map(Function f)接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
        List<String> list = Arrays.asList("aa","bb");
        list.stream().map(str -> str.toUpperCase()).forEach(System.out ::println);
        Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest::fromStringToStream);
        streamStream.forEach(s ->{
            s.forEach(System.out ::println);
        });
        //flatMap(Function f)接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
        Stream<Character> characterStream = list.stream().flatMap(StreamAPITest::fromStringToStream);
        characterStream.forEach(System.out::println);
    }
    //将字符串中多个字符构成的集合转换为对应的Stream的实例
    public static Stream<Character> fromStringToStream(String str){
        ArrayList<Character> list = new ArrayList<>();
        for (Character c : str.toCharArray()){
            list.add(c);
        }
        return list.stream();
    }

中间操作:排序

public class StreamAPITest {
    //排序
    @Test
    public void test2() {
        //sorted()——自然排序
        List<Integer> list = Arrays.asList(12, 43, 11, 22, 8, 16);
        list.stream().sorted().forEach(System.out::println);
        //抛异常,原因:Employee没有实现Comparable接口
//        List<Employee> employees = EmployeeData.getEmployees();
//        employees.stream().sorted().forEach(System.out::println);
        //sorted(Comparator com)——定制排序
        List<Employee> employees = EmployeeData.getEmployees();
        employees.stream().sorted((e1,e2) -> {
            return Integer.compare(e1.getAge(),e2.getAge());
        }).forEach(System.out::println);
    }
}

终止操作:匹配与查找

public class StreamAPITest {
    //匹配与查找
    @Test
    public void test2() {
        List<Employee> employees = EmployeeData.getEmployees();
//        allMatch(Predicate p) 检查是否匹配所有元素
        boolean allMatch = employees.stream().allMatch(e ->e.getAge() > 18);
        System.out.println(allMatch);
//        anyMatch(Predicate p) 检查是否至少匹配一个元素
        boolean anyMatch = employees.stream().anyMatch(e ->e.getAge() > 18);
        System.out.println(anyMatch);
//        noneMatch(Predicate p) 检查是否没有匹配所有元素
        boolean noneMatch = employees.stream().noneMatch(e ->e.getAge() > 100);
        System.out.println(noneMatch);
//        findFirst() 返回第一个元素
        Optional<Employee> employee = employees.stream().findFirst();
        System.out.println(employee);
//        forEach(Consumer c) 内部迭代
        employees.stream().forEach(System.out::println);
        //使用集合的遍历操作
        employees.forEach(System.out::println);
    }
}

终止操作:归约

    //归约
    @Test
    public void test2() {
//        reduce(T identity, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 T
        //计算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);

//        reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 Optional<T>
        List<Employee> employees = EmployeeData.getEmployees();
        Stream<Double> salaryStream = employees.stream().map(Employee::getSalary);
        Optional<Double> sumMoney = salaryStream.reduce(Double::sum);
        System.out.println(sumMoney);
    }

终止操作:收集

    //收集
    @Test
    public void test2() {
//        collect(Collector c)将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
        List<Employee> employees = EmployeeData.getEmployees();
        List<Employee> employeeList = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
        employeeList.forEach(System.out::println);

        Set<Employee> employeeSet = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
        employeeSet.forEach(System.out::println);
    }
;