一、网络编程

    1.1 主机类
    对于主机IP的获取等操作,我们可以通过Inet4Address来获取。

    1.2 网络协议 - TCP/UDP协议簇
    TCP:

    1. 流传输协议
    2. 可靠传输,不会丢包
    3. 点对点通信, 传输效率偏低。

    UDP:

    1. 包传输协议
    2. 不可靠传输,会丢包
    3. 点对多通信, 传输效率高

    1.3 TCP接口简单使用

    1. @Test
    2. public void Server() throws IOException {
    3. // 创建TCP连接
    4. ServerSocket serverSocket = new ServerSocket(8899);
    5. // 监听起来
    6. Socket accept = serverSocket.accept();
    7. InputStream inputStream = accept.getInputStream();
    8. // 为了防止汉子读取读了一半导致的解析错误
    9. ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    10. // buffer缓冲
    11. byte[] buffer = new byte[1024];
    12. int size = 0;
    13. while ((size = inputStream.read(buffer)) != -1) {
    14. // 让byteArrayOutputStream存储数据
    15. byteArrayOutputStream.write(buffer, 0, size);
    16. }
    17. // 最后进行数据处理
    18. System.out.println(byteArrayOutputStream.toString());
    19. inputStream.close();
    20. serverSocket.close();
    21. }
    22. @Test
    23. public void client() throws IOException {
    24. // 获取IP地址
    25. InetAddress ip = InetAddress.getByName("127.0.0.1");
    26. // 创建TCP连接
    27. Socket socket = new Socket(ip, 8899);
    28. // 获取写入数据流
    29. OutputStream outputStream = socket.getOutputStream();
    30. outputStream.write("你好,我是客户端".getBytes());
    31. outputStream.close();
    32. socket.close();
    33. }
    34. /**
    35. * 服务器端
    36. */
    37. @Test
    38. public void server() throws IOException {
    39. // 1. 创建服务器TCP, 并且绑定端口8300
    40. ServerSocket server = new ServerSocket(8300);
    41. // 2. TCP监听
    42. Socket accept = server.accept();
    43. InputStream inputStream = accept.getInputStream();
    44. // 接受客户端的请求内容
    45. ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    46. // 服务器接受客户端的请求
    47. byte[] buffer = new byte[1024];
    48. int size = 0;
    49. while ((size = inputStream.read(buffer)) != -1) {
    50. byteArrayOutputStream.write(buffer, 0, size);
    51. }
    52. System.out.println("接受客户端的请求内容: " + byteArrayOutputStream.toString());
    53. // 服务器从本地读取文件,返回给客户端
    54. // 服务器读取本地文件
    55. FileInputStream fileInputStream = new FileInputStream("E:\\test02.jpeg");
    56. OutputStream outputStream = accept.getOutputStream();
    57. while ((size = fileInputStream.read(buffer)) != -1) {
    58. // 返回给客户端
    59. outputStream.write(buffer, 0, size);
    60. }
    61. outputStream.flush();
    62. System.out.println("返回给客户端数据成功!");
    63. fileInputStream.close();
    64. inputStream.close();
    65. outputStream.close();
    66. }
    67. ----------------------------------------------------------------------------------------
    68. /**
    69. * 客户端
    70. */
    71. @Test
    72. public void client() throws IOException {
    73. InetAddress ip = InetAddress.getByName("127.0.0.1");
    74. Socket client = new Socket(ip, 8300);
    75. OutputStream outputStream = client.getOutputStream();
    76. InputStream inputStream = client.getInputStream();
    77. byte[] buffer = new byte[1024];
    78. int size = 0;
    79. // 向服务器发送请求
    80. outputStream.write("请求服务器发送图片数据".getBytes());
    81. client.shutdownOutput();
    82. // 读取服务器内容
    83. FileOutputStream fileOutputStream = new FileOutputStream("E:\\yangjing.jpeg");
    84. while ((size = inputStream.read(buffer)) != -1) {
    85. fileOutputStream.write(buffer, 0, size);
    86. }
    87. fileOutputStream.close();
    88. inputStream.close();
    89. outputStream.close();
    90. }

    1.4 UDP协议使用

        @Test
        public void sender() throws IOException {
            // 创建UDP Socker
            DatagramSocket udpClient = new DatagramSocket();
            InetAddress ip = InetAddress.getByName("127.0.0.1");
    
            String data = "我是UDP协议通信";
            // 创建UDP包处理
            DatagramPacket datagramPacket = new DatagramPacket(data.getBytes(), 0, data.getBytes().length, ip, 8400);
            udpClient.send(datagramPacket);
            udpClient.close();
        }
    
        @Test
        public void receiver() throws IOException {
            // 创建UDP Socker
            DatagramSocket udpServer = new DatagramSocket(8400);
            byte[] buffer = new byte[1024];
            // 创建包
            DatagramPacket datagramPacket = new DatagramPacket(buffer, 0, buffer.length);
            udpServer.receive(datagramPacket);
            System.out.println(datagramPacket.getData().toString());
            udpServer.close();
        }
    

    1.5 URL

    请求路径,Java提供Url类,可以对请求的类进行访问操作。

        public static void main(String[] args) throws IOException {
            URL url = new URL("https://www.baidu.com");
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.connect();;
            // 获取到浏览器访问的资源, 可以进行后续的操作
            InputStream is = connection.getInputStream();
        }
    

    读取db.properties配置文件

        public static void main(String[] args) throws IOException {
            Properties properties = new Properties();
            FileInputStream fileInputStream = new FileInputStream("db.properties");
            properties.load(fileInputStream);
    
            String driverClass = properties.getProperty("prop.driverClass");
            System.out.println(driverClass);
        }
    

    二、反射

    2.1 反射概念
    不再使用new创建对象,而是在运行阶段通过类的class获取创建对象。可以在运行阶段动态创建对象。

    2.2 反射实现
    1、通过构造器创建类对象。

        public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
            // 1. 通过反射创建对象
            Class<User> userClass = User.class;
            Constructor<User> constructor = userClass.getConstructor(String.class, Integer.class, Long.class);
            User haomengwu = constructor.newInstance("haomengwu", 12, 560L);
            System.out.println(haomengwu);
            // 2. 通过反射,设置对象中的内容
            Field name = userClass.getDeclaredField("name");
            name.set(haomengwu, "sadas");
            // 3. 通过反射,获取对应的方法
            Method test01 = userClass.getDeclaredMethod("test01");
            test01.invoke(haomengwu);
    
            System.out.println(haomengwu);
        }
    

    2、通过实例化的对象 .getClass()

        public static void main(String[] args) throws IOException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
            User user = new User();
            Class<? extends User> aClass = user.getClass();
            Constructor<? extends User> constructor = aClass.getConstructor(String.class, Integer.class, Long.class);
            User user1 = constructor.newInstance("haomengwu", 12, 40L);
            System.out.println(user1);
        }
    

    3、通过class.forName(“path”)常见对象

        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
            String classPath = "com.hmw.reflection.User";
            Class<?> aClass = Class.forName(classPath);
            Object o = aClass.newInstance();
            System.out.println(o);
        }
    

    4、通过类加载器加载

        public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
            ClassLoader classLoader = TestClass.class.getClassLoader();
            String classPath = "com.hmw.reflection.User";
            Class<?> aClass = classLoader.loadClass(classPath);
            Object o = aClass.newInstance();
            System.out.println(o);
        }
    

    除了class类对象,其他的interface、[]、enum、annotation、基本数据类型,void都是有class对象的,我们都可以使用反射创建。
    一般JavaBean对象会提供空参的构造器,目的就是了反射直接能够抵用newInstance()方法创建,然后后面慢慢赋值,其次就是子类继承父类,容易实现父类。

    反射使用:

        // 属性   
        public static void main(String[] args) throws InstantiationException, IllegalAccessException {
            Class<User> userClass = User.class;
            // 获取User的所有public属性,包含继承的父类
            Field[] fields = userClass.getFields();
            for (Field field : fields) {
                System.out.println(field);
            }
    
            System.out.println("------------------------------");
            // 获取User的所有权限的属性,不包含父类的属性
            Field[] declaredFields = userClass.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                // 获取权限修饰符
                int modifiers = declaredField.getModifiers();
                System.out.println("权限修饰符为:" + modifiers);
    
                // 获取权限类型
                Class<?> type = declaredField.getType();
                System.out.println("权限类型:" + type);
    
                // 变量名
                String name = declaredField.getName();
                System.out.println("变量名为:" + name);
            }
        }
        // 方法
        public static void main(String[] args) throws InstantiationException, IllegalAccessException {
            Class<User> userClass = User.class;
            // 获取User类中所有public方法, 包含父类
            Method[] methods = userClass.getMethods();
            for (Method method : methods) {
                System.out.println(method);
            }
    
            System.out.println("--------------------------------------");
            // 获取User当前类中的所有权限的方法
            Method[] declaredMethods = userClass.getDeclaredMethods();
            for (Method declaredMethod : declaredMethods) {
                System.out.println("--------------------------------------");
                // 获取该方法上的所有注解
                Annotation[] annotations = declaredMethod.getAnnotations();
                for (Annotation annotation : annotations) {
                    System.out.println(declaredMethod.getName() + "----" + annotation);
                }
    
                System.out.println("方法的权限修饰符: " + Modifier.toString(declaredMethod.getModifiers()));
                System.out.println("方法的返回值类型:" + declaredMethod.getReturnType().getName());
                Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
                for (Class<?> parameterType : parameterTypes) {
                    System.out.print(declaredMethod.getName() + "方法参数:" + parameterType + " ");
                }
                System.out.println();
    
                // 获取方法可能抛出来的异常
                Class<?>[] exceptionTypes = declaredMethod.getExceptionTypes();
                for (Class<?> exceptionType : exceptionTypes) {
                    System.out.print(declaredMethod.getName() + "方法可能会抛出的一场:" + exceptionType + " ");
                }
                System.out.println();
                System.out.println("--------------------------------------");
            }
        }
        // 构造器
        public static void main7(String[] args) throws NoSuchMethodException {
            Class<User> userClass = User.class;
            // 获取当前类User的public构造器
            Constructor<?>[] constructors = userClass.getConstructors();
            for (Constructor<?> constructor : constructors) {
                System.out.println(constructor);
            }
            System.out.println("--------------------------------------");
            // 获取当前类的所有权限下的构造器
            Constructor<?>[] declaredConstructors = userClass.getDeclaredConstructors();
            for (Constructor<?> declaredConstructor : declaredConstructors) {
                System.out.println(declaredConstructor);
            }
        }
        // 获取父类的泛型名称 
        public static void main(String[] args) throws NoSuchMethodException {
            Class<User> userClass = User.class;
            // 获取当前类User的父类, 不带泛型
            Class<? super User> superclass = userClass.getSuperclass();
            System.out.println(superclass.getName());
            // 获取当前类User带泛型的父类
            Type genericSuperclass = userClass.getGenericSuperclass();
            ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
            // 获取父类的泛型名称
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            // 输出父类的泛型
            System.out.println(((Class) actualTypeArguments[0]).getName());
        }
        // 获取User类的 包、注解、实现的接口
        public static void main(String[] args) {
            Class<User> userClass = User.class;
            // 获取的当前类User实现的接口
            Class<?>[] interfaces = userClass.getInterfaces();
            for (Class<?> anInterface : interfaces) {
                System.out.println(anInterface);
            }
            // 获取User类的非泛型父类的实现的非泛型接口
            Class<?>[] interfaces1 = userClass.getSuperclass().getInterfaces();
    
            // 获取当前类User的所在包
            Package aPackage = userClass.getPackage();
            System.out.println(aPackage);
    
            // 获取当前类User的注解
            Annotation[] annotations = userClass.getAnnotations();
        }
    

    其中,通过反射可以获取类中的所有属性和注解,包括方法的返回值、修饰符、方法名、参数、注解,以及执行等等。

        // 通过反射设置属性
        public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchFieldException {
            Class<User> userClass = User.class;
            User user = userClass.newInstance();
            // 默认只能够取所有的public的属性
            Field score = userClass.getField("score");
            score.set(user, 20L);
            System.out.println(user);
    
            // 获取私有的属性
            Field name = userClass.getDeclaredField("name");
            // 私有属性需要设置Accessible才可以赋值
            name.setAccessible(true);
            name.set(user, "haomengwu");
            System.out.println(user);
    
            // 调用静态方法
            Method test03 = userClass.getMethod("test03");
            test03.invoke(user, null);
    
            // 获取到制定的 构造器
            Constructor<User> declaredConstructor = userClass.getDeclaredConstructor(String.class);
            declaredConstructor.setAccessible(true);
            declaredConstructor.newInstance();
        }
    

    2.3 静态代理和动态代理

    代理类帮助我们创建对象。并且在创建的基础上还可以做一些扩充。
    静态代理:

    // 基础接口
    interface ClothFactory {
        void produceCloth();
    }
    // 代理工厂类
    class ProxyClothFactory implements ClothFactory {
        private ClothFactory clothFactory;
    
        public ProxyClothFactory(ClothFactory clothFactory) {
            this.clothFactory = clothFactory;
        }
    
        @Override
        public void produceCloth() {
            System.out.println("代理工厂做一些准备工作");
            clothFactory.produceCloth();
            System.out.println("代理工厂做了一些后续的收尾工作");
        }
    }
    
    /**
     * 被代理类
     */
    class NickClothFactory implements ClothFactory {
        @Override
        public void produceCloth() {
            System.out.println("NickClothFactory做了一些操作");
        }
    }
    
    class JennyClothFactory implements ClothFactory {
        @Override
        public void produceCloth() {
            System.out.println("JennyClothFactory做一些操作");
        }
    }
    
    public class StaticProxy {
        public static void main(String[] args) {
            NickClothFactory nickClothFactory = new NickClothFactory();
            ProxyClothFactory proxyClothFactory = new ProxyClothFactory(nickClothFactory);
            proxyClothFactory.produceCloth();
    
            JennyClothFactory jennyClothFactory = new JennyClothFactory();
            ProxyClothFactory proxyClothFactory1 = new ProxyClothFactory(jennyClothFactory);
            proxyClothFactory1.produceCloth();
        }
    }
    

    动态代理:

    /**
     * 基础类
     */
    interface Car {
        String carName();
        void havior(String carName);
    }
    
    /**
     * 被代理类
     */
    class BaoMaCar implements Car {
        @Override
        public String carName() {
            return "我爱你,杨靖";
        }
    
        @Override
        public void havior(String carName) {
            System.out.println(carName + " 车运行起来啦");
        }
    }
    
    /**
     * 代理工厂, 使用Proxy.newInstance()代理对象
     */
    class ProxyFactory {
        public static Object getProxyInstance(Object obj) {
            MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
            myInvocationHandler.bind(obj);
            return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), myInvocationHandler);
        }
    }
    
    class MyInvocationHandler implements InvocationHandler {
    
        private Object object;
    
        public void bind(Object object) {
            this.object = object;
        }
    
        // 当代理类调用方法a时,会自动调用如下代码
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 执行代理类调用的方法,也就是被代理类执行的方法
            Object invoke = method.invoke(object, args);
            return invoke;
        }
    }
    
    public class DynamicFactory {
        public static void main(String[] args) {
            BaoMaCar baoMaCar = new BaoMaCar();
            Car proxyInstance = (Car)ProxyFactory.getProxyInstance(baoMaCar);
            // 执行被代理类的方法
            System.out.println(proxyInstance.carName());
            proxyInstance.havior("好萌物");
            System.out.println(proxyInstance);
        }
    }
    

    所以AOP切面是基于代理实现的,代理的功能很简单,主要是帮助我们调用方法。它的好处在于可以在调用方法的前后添加一些新的方法。 从而达到切面的效果。

    三、Java8新特性

    3.1 Lambda表达式

    -> Lambda操作符 -> 左边是形参列表 -> 右边是Lambda体

    Lambda的本质是一个对象的实例。
    image.png
    image.png
    总结:
    1、Lambda形参左边的参数可以省略(会自动类型推断);如果Lanbda形参列表只有一个参数, 这一对小括号()可以省略。
    2、Lambda如果只有一个执行语句(可能是reuturn),则可以省略一对{}和ruturn。
    本质上Lambda就是实例化一个继承接口的类对象,并且完成接口方法的重写。 如果一个类对象继承很多个接口,则会找不到继承哪个接口,从而无法实例化,使用Lambda。

    3.2 函数式接口

    如果一个接口只声明了一个抽象方法, 则这个接口就是函数式接口。
    可以使用@FunctionalInterface校验是否为函数式接口。这是Java为了支持OOF的扩展。

    虽然说Lambda在Py语言等都是函数式,Java为了支持,但又不影响自己OOP编程思想,因此Lambda在Java中是创建了匿名对象的。

    如果说一个接口是函数式接口,那么这个接口就可以使用Lambda创建。
    image.png

    3.3 方法引用和构造器引用

    方法引用本身其实就是Lombda,创建一个对象。
    使用方法引用,必须要保证=左边的参数类型和返回值和=右边的参数类型和返回值相同。
    非静态方法可以被class对象和实例化对象访问,而静态方法只能被class对象访问

    方法引用的本质就是重写的方法和 传入重写的方法参数和返回值相同。

    // 保证了 Consumer 中的accept方法的参数和返回值类型和 println 参数和返回值相同    
    Consumer<String> stringConsumer = System.out::println;
    
    // lambda
    Comparator<Integer> Comparator1 = (o1, o2) -> Integer.compare(o1, o2);
    // 方法引用    
    Comparator<Integer> comparator2 = Integer::compare;
    

    构造器引用:

            // 匿名类
            Supplier<User> supplier1 = new Supplier<User>() {
                @Override
                public User get() {
                    return new User();
                }
            };
            // Lambda
            Supplier<User> supplier2 = () -> new User();
            // 构造器引用
            Supplier<User> supplier = User::new; 
    
    
            BiFunction<Integer, String, User> biFunction = new
                    BiFunction<Integer, String, User>() {
                        @Override
                        public User apply(Integer integer, String s) {
                            return new User(integer, s);
                        }
                    };
            BiFunction<Integer, String, User> biFunction1 = (age, name) -> new User(age, name);
            BiFunction<Integer, String, User> biFunction2 = User::new;
    

    数组引用:

            Function<Integer, String[]> function = new Function<Integer, String[]>() {
                @Override
                public String[] apply(Integer integer) {
                    return new String[integer];
                }
            };
    
            Function<Integer, String[]> function1 = (length) -> new String[length];
            Function<Integer, String[]> function2 = String[]::new;
    

    牛逼程度: 数组引用 > Lambda > 匿名类 > 继承重写,调用

    三、StreamAPI操作

    StreamAPI是对集合的关键抽象概念,可以对相应的集合进行复杂的查找、过滤、映射数据操作。

    1. stream自己不会存储元素
    2. stream不会改变原有对象,还是返回一个新的stream
    3. stream操作是延迟执行的,当需要结果的时间才会真正的执行。

    image.png

    只要不调用中止操作,都不会执行,只要当执行了中止操作才会真正执行。 当执行了中止操作,而不会再执行操作了。

    3.1 StreamAPI中间操作流

    1)filter过滤流

            List<User> list = new ArrayList<>();
            list.add(new User(10, "haomengwu"));
            list.add(new User(20, "yangjing"));
            list.add(new User(30, "wang"));
            Stream<User> stream = list.stream();
            stream.filter(e -> e.getAge() > 20).forEach(System.out::println);
    

    2)limit拦截流
    limit(n) 保存前n个,n+1后面的不要

        public static void main(String[] args) {
            List<User> list = new ArrayList<>();
            list.add(new User(10, "haomengwu"));
            list.add(new User(20, "yangjing"));
            list.add(new User(30, "wang"));
            list.stream().limit(2).forEach(System.out::println);
        }
    

    3)skip拦截流
    skip(n) 跳过前n个流,只保留n后面的流。

        public static void main(String[] args) {
            List<User> list = new ArrayList<>();
            list.add(new User(10, "haomengwu"));
            list.add(new User(20, "yangjing"));
            list.add(new User(30, "wang"));
            list.stream().skip(2).forEach(System.out::println);
        }
    

    4)distinct去重流
    被包装的类需要实现equals()和hasCode(), 去重通过这个实现

        public static void main(String[] args) {
            List<User> list = new ArrayList<>();
            list.add(new User(10, "haomengwu"));
            list.add(new User(20, "yangjing"));
            list.add(new User(30, "wang"));
            list.add(new User(30, "wang"));
            list.stream().distinct().forEach(System.out::println);
        }
    

    4)map(Function) 接受一个函数作为参数,将返回值的流作为后续操作的入参
    map(Function) 返回的是Stream流,实际上就是将Function返回值作为Stream返回

        public static void main(String[] args) {
            List<User> list = new ArrayList<>();
            list.add(new User(10, "haomengwu"));
            list.add(new User(20, "yangjing"));
            list.add(new User(30, "wang"));
            list.add(new User(30, "wang1"));
    
            list.stream().map(User::getAge).filter(e -> e > 10).forEach(System.out::println);
            list.stream().map(User::getName).filter(e -> e.length() > 7).forEach(System.out::println);
        }
    

    5)flatmap(Function) 接受一个函数作为参数,将返回值的流作为后续操作的入参
    flatMap(Function) 和map的区别在于存放的元素是Stream, 再加上外部返回的Stream, Map不好处理,flatMap便于操作。
    image.png
    6)sorted() 排序
    自定义对象需要实现equals和hashCode。

        public static void main(String[] args) {
            List<String> list = Arrays.asList("aa", "cc", "bb", "dd");
            list.stream().sorted().forEach(System.out::println);
    
            List<User> listUser = new ArrayList<>();
            listUser.add(new User(1, "hao"));
            listUser.add(new User(2, "hao"));
            listUser.add(new User(1, "zao"));
    
            listUser.stream().sorted((e1, e2) -> {
                if(e1.getAge() > e2.getAge()) {
                    return 1;
                } else if (e1.getAge() < e2.getAge()) {
                    return  -1;
                } else {
                    return e1.getName().compareTo(e2.getName());
                }
            }).forEach(System.out::println);
        }
    

    3.3 Stream中止操作流
    image.png

        public static void main5(String[] args) {
            List<Integer> list = Arrays.asList(1,4,5,3,2,7);
            // 全部成立 返回true
            boolean b = list.stream().allMatch(e -> e > 0);
            System.out.println(b);
            // 全部不成立 返回true
            boolean b1 = list.stream().noneMatch(e -> e <= 1);
            System.out.println(b1);
            // 获取第一个类型
            Optional<Integer> first = list.stream().findFirst();
            System.out.println(first.get());
            // 获取流中任意一个元素
            Optional<Integer> any = list.stream().findAny();
            System.out.println(any.get());
    
            long count = list.stream().filter(e -> e > 0).count();
            System.out.println(count);
        }
    
        public static void main(String[] args) {
            List<User> listUser = new ArrayList<>();
            listUser.add(new User(1, "hao"));
            listUser.add(new User(2, "hao"));
            listUser.add(new User(3, "zao"));
    
            // 获取集合中年龄最大的值
            Optional<Integer> max = listUser.stream().map(User::getAge).max((e1, e2) -> {
                return Integer.compare(e1, e2);
            });
            Optional<Integer> max1 = listUser.stream().map(User::getAge).max(Integer::compare);
            System.out.println(max.get());
    
            // 获取集合中年龄最小的对象
            Optional<User> min = listUser.stream().min((e1, e2) -> {
                return Integer.compare(e1.getAge(), e2.getAge());
            });
            System.out.println(min.get());
        }
    

    规约操作:

    使用map做映射,提取相关的数据,然后再使用reduce进行规约。对提取的数据进行总计操作。

    reduce(T identity, BinaryOperator) - 将流中的元素反复结合起来,得到一个值

        public static void main(String[] args) {
            List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
            BinaryOperator<Integer> binaryOperator = new BinaryOperator<Integer>() {
                @Override
                public Integer apply(Integer integer, Integer integer2) {
                    return Integer.sum(integer, integer2);
                }
            };
            BinaryOperator<Integer> binaryOperatorLambda = (e1, e2) -> { return Integer.sum(e1, e2); };
            BinaryOperator<Integer> binaryOperatorMethodRef = Integer::sum;
            Integer reduce = list.stream().reduce(0, Integer::sum);
            System.out.println("reduce = " + reduce);
    
            List<User> userList = new ArrayList<>();
            userList.add(new User(1, "h"));
            userList.add(new User(10, "h"));
            userList.add(new User(100, "h"));
            userList.add(new User(1000, "h"));
    
            Integer reduce1 = userList.stream().map(User::getAge).reduce(0, StreamAPITest::sum);
            System.out.println(reduce1);
        }
    
        public static int sum(Integer integer, Integer integer1) {
            return Integer.sum(integer, integer1);
        }
    

    收集操作:
    image.png

        public static void main(String[] args) {
            List<User> userList = new ArrayList<>();
            userList.add(new User(1, "h"));
            userList.add(new User(10, "h"));
            userList.add(new User(100, "h"));
            userList.add(new User(1000, "h"));
    
            List<Integer> collect = userList.stream().map(User::getAge).collect(Collectors.toList());
            List<String> collect1 = userList.stream().map(User::getName).collect(Collectors.toList());
            List<String> collect2 = userList.stream().map((e) -> String.valueOf(e.getAge())).collect(Collectors.toList());
        }
    

    四、Optional类

    解决了空指针异常的问题。为了避免程序中出现空指针异常。
    image.png

    public class OptionalTest {
        public static void main(String[] args) {
            // optional.of(A) A不能为空
            Optional<User> asd = Optional.of(new User(1, "asd", null));
            System.out.println(asd);
            // optional.ofNullable(B) B 可以为空
            Object hehe = Optional.ofNullable(null).orElse(new User(2, "hehe", null));
            System.out.println(hehe);
    
            test0111(new User(10, "heheh", null));
        }
    
        public static void test0111(User user) {
            User user1 = Optional.ofNullable(user).orElse(new User(1, "杨靖", new Integer[10]));
            Integer[] arr = Optional.ofNullable(user1.getArr()).orElse(new Integer[5]);
        }
    }
    

    五、JDK9、10、11新特性

    jdk需要9,10,11的版本才可以使用如下功能。