• Java8(JDK1.8)新特性


    一、Java8(JDK1.8)新特性

    1、Lamdba表达式

    2、函数式接口

    3、方法引用和构造引用

    4、Stream API

    5、接口中的默认方法和静态方法

    6、新时间日期API

    7、OPtional

    8、其他特性

    二、java8(JDK1.8)新特性简介

    1、速度快;

    2、代码少、简介(新增特性:lamdba表达式);

    3、强大的Stream API;

    4、使用并行流和串行流;

    5、最大化较少空指针异常Optional;

    其中最为核心的是Lambda表达式和Stream API

    三、java8(JDK1.8)新特性详细介绍

    一、Lambda表达式

    1、Lambda表达式是什么?

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

    2、从匿名类到Lambda转换

    1. package com.chen.test.JAVA8Features;
    2. import org.slf4j.Logger;
    3. import org.slf4j.LoggerFactory;
    4. public class Demo01 {
    5.    private static Logger log = LoggerFactory.getLogger(Demo01.class);
    6.    public static void main(String[] args) {
    7.        Runnable t1 =new Runnable(){
    8.            @Override
    9.            public void run(){
    10.                log.info("我是没有使用Lambda表达式:不简洁");
    11.           }
    12.       };
    13.        
    14.        Runnable t2 = () -> log.info("我是使用Lambda表达式:简洁、灵活");
    15.        
    16.        t1.run();
    17.        t2.run();
    18.        
    19.   }
    20. }

    Run result

    1. 19:43:39.303 [main] INFO com.chen.test.JAVA8Features.Demo01 - 我是没有使用Lambda表达式:不简洁、代码多
    2. 19:43:39.303 [main] INFO com.chen.test.JAVA8Features.Demo01 - 我是使用Lambda表达式:简洁、灵活
    3. Process finished with exit code 0

    3、Lambda表达式语法

    Lambda表达式在java语言中引入了一种新的语法元素和操作。这种操作符号为“->”,Lambda操作符或箭头操作符,它将Lambda表达式分割为两部分。 左边:指Lambda表达式的所有参数 右边:指Lambda体,即表示Lambda表达式需要执行的功能。

    六种语法格式:

    1、语法格式一:无参数、无返回值,只需要一个Lambda体

    1. package com.chen.test.JAVA8Features;
    2. import org.slf4j.Logger;
    3. import org.slf4j.LoggerFactory;
    4. public class Demo02 {
    5.    private static Logger log = LoggerFactory.getLogger(Demo02.class);
    6.    public static void main(String[] args) {
    7.        Runnable t1 = ()-> log.info("Lambda表达式:简洁、灵活,优雅永不过时");
    8.        t1.run();
    9.   }
    10. }
     
    

    run result

    1. 22:22:39.125 [main] INFO com.chen.test.JAVA8Features.Demo02 - Lambda表达式:简洁、灵活,优雅永不过时
    2. Process finished with exit code 0

    2、语法格式二:lambda有一个参数、无返回值

    1. package com.chen.test.JAVA8Features;
    2. import org.slf4j.Logger;
    3. import org.slf4j.LoggerFactory;
    4. import java.util.function.Consumer;
    5. public class Demo03 {
    6.    private static Logger log = LoggerFactory.getLogger(Demo03.class);
    7.    public static void main(String[] args) {
    8.        Consumer consumer = new Consumer() {
    9.            @Override
    10.            public void accept(String s) {
    11.                log.info(s);
    12.           }
    13.       };
    14.        consumer.accept("爱与被爱的区别");
    15.        Consumer consumer1 = (s) -> log.info(s);
    16.        consumer1.accept("接受爱不一定爱对方,爱一定付出真心爱");
    17.   }
    18. }

    run result

    1. 23:03:08.992 [main] INFO com.chen.test.JAVA8Features.Demo03 - 爱与被爱的区别
    2. 23:03:09.142 [main] INFO com.chen.test.JAVA8Features.Demo03 - 接受爱不一定爱对方,爱一定付出真心爱
    3. Process finished with exit code 0

    3、语法格式三:Lambda只有一个参数时,可以省略()

    1. package com.chen.test.JAVA8Features;
    2. import org.slf4j.Logger;
    3. import org.slf4j.LoggerFactory;
    4. import java.util.function.Consumer;
    5. public class Demo04 {
    6.    private static Logger log = LoggerFactory.getLogger(Demo04.class);
    7.    public static void main(String[] args) {
    8.        Consumer consumer = s -> log.info(s);
    9.        consumer.accept("Lambda只有一个参数时,可以省略()");
    10.   }
    11. }

    run result

    1. 23:08:27.295 [main] INFO com.chen.test.JAVA8Features.Demo04 - Lambda只有一个参数时,可以省略()
    2. Process finished with exit code 0

    4、语法格式四:Lambda有两个参数时,并且有返回值

    1. package com.chen.test.JAVA8Features;
    2. import org.slf4j.Logger;
    3. import org.slf4j.LoggerFactory;
    4. import java.util.Comparator;
    5. public class Demo05 {
    6.    private static Logger log = LoggerFactory.getLogger(Demo05.class);
    7.    public static void main(String[] args) {
    8.        CompareOldMethod(12,10);
    9.        findMaxValue(12,10);
    10.        findMinValue(12,10);
    11.   }
    12. //   没有使用Lambda表达式比较大小
    13.    public static void CompareOldMethod(int num1,int num2){
    14.        Comparator comparator = new Comparator() {
    15.            @Override
    16.            public int compare(Integer o1, Integer o2) {
    17.                log.info("o1:{}",o1);
    18.                log.info("o2:{}",o2);
    19.                return o1 < o2 ? o2 : o1;
    20.           }
    21.       };
    22.        log.info("OldFindMaxValue:{}",comparator.compare(num1,num2));
    23.   }
    24. //   使用lambda表达式
    25.    public static void findMaxValue(int num1,int num2){
    26.        Comparator comparatorMax = (o1, o2) ->{
    27.            log.info("o1:{}",o1);
    28.            log.info("o2:{}",o2);
    29.            return (o1
    30.       };
    31.        log.info("findMaxValue:{}",(comparatorMax.compare(num1,num2)));
    32.   }
    33.    public static void findMinValue(int num1,int num2){
    34.        Comparator comparatorMin = (o1, o2) -> {
    35.            log.info("o1:{}",o1);
    36.            log.info("o2:{}",o2);
    37.            return (o1 < o2) ? o1 : o2;
    38.       };
    39.        log.info("FindMinValue:{}",comparatorMin.compare(num1,num2));
    40.   }
    41. }

    run result

    1. 00:17:10.206 [main] INFO com.chen.test.JAVA8Features.Demo05 - o1:12
    2. 00:17:10.206 [main] INFO com.chen.test.JAVA8Features.Demo05 - o2:10
    3. 00:17:10.206 [main] INFO com.chen.test.JAVA8Features.Demo05 - OldFindMaxValue:12
    4. 00:17:10.315 [main] INFO com.chen.test.JAVA8Features.Demo05 - o1:12
    5. 00:17:10.315 [main] INFO com.chen.test.JAVA8Features.Demo05 - o2:10
    6. 00:17:10.315 [main] INFO com.chen.test.JAVA8Features.Demo05 - findMaxValue:12
    7. 00:17:10.315 [main] INFO com.chen.test.JAVA8Features.Demo05 - o1:12
    8. 00:17:10.315 [main] INFO com.chen.test.JAVA8Features.Demo05 - o2:10
    9. 00:17:10.315 [main] INFO com.chen.test.JAVA8Features.Demo05 - FindMinValue:10
    10. Process finished with exit code 0

    5、语法格式五:当Lambda体只有一条语句的时候,return和{}可以省略掉

    1. package com.chen.test.JAVA8Features;
    2. import org.slf4j.Logger;
    3. import org.slf4j.LoggerFactory;
    4. import java.util.Comparator;
    5. public class Demo05 {
    6.    private static Logger log = LoggerFactory.getLogger(Demo05.class);
    7.    public static void main(String[] args) {
    8.        findMaxValue(12,10);
    9.        findMinValue(12,10);
    10.   }
    11. //   使用lambda表达式
    12.    public static void findMaxValue(int num1,int num2){
    13.        Comparator comparatorMax = (o1, o2) ->{
    14.            log.info("o1:{}",o1);
    15.            log.info("o2:{}",o2);
    16.            return (o1
    17.       };
    18.        log.info("findMaxValue:{}",(comparatorMax.compare(num1,num2)));
    19.   }
    20.    public static void findMinValue(int num1,int num2){
    21.        Comparator comparatorMin = (o1, o2) -> (o1 < o2) ? o1 : o2;
    22.        log.info("FindMinValue:{}",comparatorMin.compare(num1,num2));
    23.   }
    24. }

    run result

    1. 00:22:31.059 [main] INFO com.chen.test.JAVA8Features.Demo05 - o1:12
    2. 00:22:31.075 [main] INFO com.chen.test.JAVA8Features.Demo05 - o2:10
    3. 00:22:31.075 [main] INFO com.chen.test.JAVA8Features.Demo05 - findMaxValue:12
    4. 00:22:31.075 [main] INFO com.chen.test.JAVA8Features.Demo05 - FindMinValue:10
    5. Process finished with exit code 0

    6、语法格式六:类型推断:数据类型可以省略,因为编译器可以推断得出,成为“类型推断”

    1. package com.chen.test.JAVA8Features;
    2. import com.mysql.cj.callback.MysqlCallbackHandler;
    3. import org.slf4j.Logger;
    4. import org.slf4j.LoggerFactory;
    5. import java.util.ArrayList;
    6. import java.util.Comparator;
    7. import java.util.List;
    8. import java.util.function.Consumer;
    9. public class Demo07 {
    10.    private static Logger log = LoggerFactory.getLogger(Demo07.class);
    11.    public static void main(String[] args) {
    12.        dateType();
    13.   }
    14.    public static void dateType(){
    15.        Consumer consumer = (String s) -> log.info(s);
    16.        consumer.accept("Hello World !");
    17.        Consumer consumer1 = (s) -> log.info(s);
    18.        consumer1.accept("Hello don't date type !");
    19.   }
    20. }

    二、函数式接口

    1、什么是函数式接口?

    函数式接口:只包含一个抽象方法的接口,称为函数式接口,并且可以使用lambda表达式来创建该接口的对象,可以在任意函数式接口上使用@FunctionalInterface注解,来检测它是否是符合函数式接口。同时javac也会包含一条声明,说明这个接口是否符合函数式接口。

    2、自定义函数式接口

    1. package com.chen.test.JAVA8Features;
    2. @FunctionalInterface
    3. public interface FunctionDemo1 {
    4.    public void fun();
    5. }

    3、泛型函数式接口

    1. package com.chen.test.JAVA8Features;
    2. @FunctionalInterface
    3. public interface FunctionGeneric {
    4.    public void fun(T t);
    5. }

    4、java内置函数式接口

    (Function、Consumer、Supplier、Predicate) java.util.function

    Function (函数型接口)

    函数型接口:有输入参数,也有返回值。

    1. * @param the type of the input to the function
    2. * @param the type of the result of the function
    3. *
    4. * @since 1.8
    5. */
    6. @FunctionalInterface
    7. public interface Function {
    8.    /**
    9.     * Applies this function to the given argument.
    10.     *
    11.     * @param t the function argument
    12.     * @return the function result
    13.     */
    14.    R apply(T t);

    其中T表示输入参数,R为返回值

    代码展示:

    1.    public void functionTest(){
    2. //       Function function = new Function(){
    3. //           @Override
    4. //           public String apply(String s) {
    5. //               return s;
    6. //           }
    7. //       };
    8. //       log.info("函数型接口 :{}",function.apply("没有使用Lambda表达式"));
    9.        Function function = s -> s;
    10.        log.info("函数型接口:{}",function.apply("Function Demo"));
    11.   }

    Consumer(消费型接口)

    消费型接口:有入参,没有会有返回值

    1. * @param the type of the input to the operation
    2. *
    3. * @since 1.8
    4. */
    5. @FunctionalInterface
    6. public interface Consumer {
    7.    /**
    8.     * Performs this operation on the given argument.
    9.     *
    10.     * @param t the input argument
    11.     */
    12.    void accept(T t);

    代码展示:

       
    
    1.  public void consumerTest(){
    2. //       非Lambda表达式
    3. //       Consumer consumer = new Consumer() {
    4. //           @Override
    5. //           public void accept(String s) {
    6. //               log.info(s);
    7. //           }
    8. //       };
    9. //       consumer.accept("消费型函数:没有使用Lambda表达式");
    10. //       使用Lambda表达式
    11.        Consumer consumer = s -> log.info(s);
    12.        consumer.accept("消费型函数:Consumer Demo");
    13.   }

    Supplier(供给型接口)

    供给型接口:没有输入参数,有返回值

    1. *
    2. * @param the type of results supplied by this supplier
    3. *
    4. * @since 1.8
    5. */
    6. @FunctionalInterface
    7. public interface Supplier {
    8.    /**
    9.     * Gets a result.
    10.     *
    11.     * @return a result
    12.     */
    13.    T get();
    14. }

    代码展示:

      
    1.  public void supplierTest(){
    2. //       非Lambda表达式
    3. //       Supplier supplier = new Supplier(){
    4. //           @Override
    5. //           public String get() {
    6. //               return "供给型接口:没有使用Lambda表达式";
    7. //           }
    8. //       };
    9. //       log.info(String.valueOf(supplier.get()));
    10.        Supplier supplier = () -> "供给型接口:Supplier Demo";
    11.        log.info(String.valueOf(supplier.get()));
    12.   }

    Predicate(断定型接口)

    断言型接口:既有输入参数也有返回值,返回类型是boolean类型

    1. * @param the type of the input to the predicate
    2. *
    3. * @since 1.8
    4. */
    5. @FunctionalInterface
    6. public interface Predicate {
    7.    /**
    8.     * Evaluates this predicate on the given argument.
    9.     *
    10.     * @param t the input argument
    11.     * @return {@code true} if the input argument matches the predicate,
    12.     * otherwise {@code false}
    13.     */
    14.    boolean test(T t);

    展示代码:

        
    1. public void predicateTest() {
    2. //       Predicate predicate = new Predicate() {
    3. //           @Override
    4. //           public boolean test(String s) {
    5. //               return s.equals("Predicate Demo");
    6. //           }
    7. //       };
    8. //       log.info("断言型接口:{}",predicate.test("没有使用Lambda表达式"));
    9.        Predicate predicate = s -> s.equals("Predicate Demo");
    10.        log.info("断言型接口:{}",predicate.test("Predicate Demo"));
    11.   }

    java内置四种大函数式接口,可以使用Lambda表达式

    1. package com.chen.test.JAVA8Features;
    2. import com.google.common.base.Function;
    3. import org.slf4j.Logger;
    4. import org.slf4j.LoggerFactory;
    5. import java.util.function.Consumer;
    6. import java.util.function.Predicate;
    7. import java.util.function.Supplier;
    8. public class FunDemo01 {
    9.    private static Logger log = LoggerFactory.getLogger(FunDemo01.class);
    10.    public static void main(String[] args) {
    11.        FunDemo01 demo01 = new FunDemo01();
    12.        demo01.functionTest();
    13.        demo01.consumerTest();
    14.        demo01.supplierTest();
    15.        demo01.predicateTest();
    16.   }
    17.    public void functionTest(){
    18. //       非Lambda表达式
    19. //       Function function = new Function(){
    20. //           @Override
    21. //           public String apply(String s) {
    22. //               return s;
    23. //           }
    24. //       };
    25. //       log.info("函数型接口 :{}",function.apply("没有使用Lambda表达式"));
    26.        Function function = s -> s;
    27.        log.info("函数型接口:{}",function.apply("Function Demo"));
    28.   }
    29.    public void consumerTest(){
    30. //       非Lambda表达式
    31. //       Consumer consumer = new Consumer() {
    32. //           @Override
    33. //           public void accept(String s) {
    34. //               log.info(s);
    35. //           }
    36. //       };
    37. //       consumer.accept("消费型函数:没有使用Lambda表达式");
    38. //       使用Lambda表达式
    39.        Consumer consumer = s -> log.info(s);
    40.        consumer.accept("消费型函数:Consumer Demo");
    41.   }
    42.    public void supplierTest(){
    43. //       非Lambda表达式
    44. //       Supplier supplier = new Supplier(){
    45. //           @Override
    46. //           public String get() {
    47. //               return "供给型接口:没有使用Lambda表达式";
    48. //           }
    49. //       };
    50. //       log.info(String.valueOf(supplier.get()));
    51.        Supplier supplier = () -> "供给型接口:Supplier Demo";
    52.        log.info(String.valueOf(supplier.get()));
    53.   }
    54.    public void predicateTest() {
    55. //       Predicate predicate = new Predicate() {
    56. //           @Override
    57. //           public boolean test(String s) {
    58. //               return s.equals("Predicate Demo");
    59. //           }
    60. //       };
    61. //       log.info("断言型接口:{}",predicate.test("没有使用Lambda表达式"));
    62.        Predicate predicate = s -> s.equals("Predicate Demo");
    63.        log.info("断言型接口:{}",predicate.test("Predicate Demo"));
    64.   }
    65. }

    三、方法引用和构造器引用

    1、方法引用

    当要传递给Lambda体的操作已经有实现方法,可以直接使用方法引用(实现抽象方法的列表,必须要和方法引用的方法参数列表一致)

    方法引用:使用操作符“::”将方法名和(类或者对象)分割开来。

    有下列三种情况:

    1. 对象::实例方法

    2. 类::实例方法

    3. 类::静态方法

    代码展示:

    1. package com.chen.test.JAVA8Features;
    2. public class MethodRefDemo {
    3.    public static void main(String[] args) {
    4.        FunctionGeneric strName = s -> System.out.println(s);
    5.        strName.fun("Lambda表达式没有使用方法引用");
    6.        
    7.        //方法引用
    8.        FunctionGeneric strName2 = System.out::println;
    9.        strName2.fun("使用方法引用");
    10.   }
    11. }

    2、构造器引用

    本质上:构造器引用和方法引用相识,只是使用了一个new方法

    使用说明:函数式接口参数列表和构造器参数列表要一致,该接口返回值类型也是构造器返回值类型

    格式:ClassName :: new

    代码展示:

    1. package com.chen.test.JAVA8Features;
    2. import java.util.function.Function;
    3. public class MethodRefDemo {
    4.    public static void main(String[] args) {
    5.        //构造器引用
    6.        Function fun1 = (num) -> new Integer(num);
    7.        Function fun2 = Integer::new;
    8.        //数组引用
    9.        Function fun3 = (num) ->new Integer[num];
    10.        Function fun4 = Integer[]::new;
    11.   }
    12. }

    四、强大的Stream API

    1、什么是Stream?

    Java8中两个最为重要特性:第一个的是Lambda表达式,另一个是Stream API。

    StreamAPI它位于java.util.stream包中,StreamAPI帮助我们更好地对数据进行集合操作,它本质就是对数据的操作进行流水线式处理,也可以理解为一个更加高级的迭代器,主要作用是遍历其中每一个元素。简而言之,StreamAP提供了一种高效且易于使用的处理数据方式。

    2、Stream特点:

    • 1、Stream自己不会存储数据。

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

    • 3、Stream操作时延迟执行的。这就意味着它们等到有结果时候才会执行。

    • 和list不同,Stream代表的是任意Java对象的序列,且stream输出的元素可能并没有预先存储在内存中,而是实时计算出来的。它可以“存储”有限个或无限个元素。

      例如:我们想表示一个全体自然数的集合,使用list是不可能写出来的,因为自然数是无线的,不管内存多大也没法放到list中,但是使用Sream就可以

    3、Stream操作的三个步骤?

    • 1、创建Stream:一个数据源(例如:set 、list),获取一个流

    • 2、中间操作:一个中间操作连接,对数据源的数据进行处理

    • 3、终止操作:一个终止操作,执行中间操作连,产生结果。

    1、创建流

    创建流方式有多种:

    第一种:通过集合

    对于Collection接口(List 、Set、Queue等)直接调用Stream()方法可以获取Stream

        
    1.     List list = new ArrayList<>();
    2.        Stream stringStream = list.stream(); //返回一个顺序流
    3.        Stream parallelStream = list.parallelStream(); //返回一个并行流(可多线程)

    第二种:通过数组

    把数组变成Stream使用Arrays.stream()方法

    1.        Stream stream1 = Arrays.stream(new String[]{"CBB", "YJJ", "CB", "CJJ"});

    第三种:Stream.of()静态方法直接手动生成一个Stream

            Stream stream = Stream.of("A", "B", "C", "D");

    第四种:创建无限流

    1.        //迭代
    2.        //遍历10个奇数
    3.        Stream.iterate(1,t->t+2).limit(10).forEach(System.out::println);
    4.        //生成
    5.        //生成10个随机数
    6.        Stream.generate(Math::random).limit(10).forEach(System.out::println);
    第五种:自己构建

    第六种:其他等等

    2、中间操作

    一个流可以后面跟随着0个或者多个中间操作,其目的是打开流,做出某种程度的数据过滤、去重、排序、映射、跳过等。然后返回一个新的流,交给下一个使用,仅仅是调用这个方法,没有真正开始遍历。

    map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered

    3、终止操作:一个终止操作,执行中间操作连,产生结果。

    forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

    1. package com.chen.test.JAVA8Features.Stream;
    2. import java.util.*;
    3. import java.util.stream.Collectors;
    4. public class StreamDemo01 {
    5.    public static void main(String[] args) {
    6.        List list = new ArrayList<>();
    7.        for (int i = 0; i < 10; i++) {
    8.            list.add(i);
    9.       }
    10.        //map
    11.        List collect = list.stream().map(n -> n * 2).collect(Collectors.toCollection(ArrayList::new));
    12.        collect.forEach(System.out::println);
    13.        //filer 过滤
    14.        List list1 = list.stream().filter(n -> n % 2 == 0).collect(Collectors.toList());
    15.        list1.forEach(System.out::println);
    16.        //distinct 去重
    17.        List list2 = list.stream().distinct().collect(Collectors.toList());
    18.        list2.forEach(System.out::println);
    19.        //skip 跳过
    20.        List list3 = list.stream().skip(3).collect(Collectors.toList());
    21.        list3.forEach(System.out::println);
    22.        //limit 截取
    23.        Set set = list.stream().limit(3).collect(Collectors.toSet());
    24.        set.forEach(System.out::println);
    25.        //skip and limit 组合使用
    26.        List list4 = list.stream().skip(3).limit(5).collect(Collectors.toList());
    27.        list4.forEach(System.out::println);
    28.   }
    29. }

    五、接口中默认方法和静态方法

    1、默认方法

    java8允许接口中包含具体实现的方法体,该方法是默认方法,它需要使用default关键字修饰

    2、静态方法

    java8中允许接口中定义静态方法,使用static关键字修饰

    代码展示:

    1. package com.chen.test.JAVA8Features.DefaultMethod;
    2. public interface DefaultMethodDemo {
    3.    
    4.    default Integer addMethod(int a ,int b){
    5.        System.out.println("我是默认方法");
    6.        return a+b;
    7.   }
    8.    static void test(){
    9.        System.out.println("我是静态方法");
    10.   }
    11. }

    六、新时间日期接口

    七、Optional类

    optional类是一个容器,代表一个值存在或者不存在,原来使用null表示一个值存不存在,现在使用optional可以更好的表达这个概念,并且可以避免空指针异常。

    Optional常用的方法:

    1. Optional.of(T t) : 创建一个Optional实例;

    2. Optional.empty() : 创建一个空的Optional实例;

    3. Optional.ofNullable(T t) :若t不为空创建一个Optional实例否则创建一个空实例;

    4. isPresent() : 判断是否包含值;

    5. orElse(T t) :如果调用对象包含值,返回该值,否则返回t;

    6. orElseGet(Supplier s) : 如果调用对象包含值,返回该值,否则返回s获取的值;

    7. map(Function f) : 如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty();

    8. flatMap(Function mapper) : 与map类似,要求返回值必须是Optional。

    八、其他等等

  • 相关阅读:
    玩以太坊链上项目的必备技能(类型-值类型-Solidity之旅二)
    实验十 符号计算基础与符号微积分(matlab)
    计算机毕业设计之java+javaweb的医院门诊挂号系统
    08:STM32----DMA数据转运
    PDF格式分析(七十三)——链接注释
    使用webdriver-manager解决浏览器与驱动不匹配所带来自动化无法执行的问题
    java-php-python-基于SSM框架的企业机械设备智能管理系统的设计与实现计算机毕业设计
    我也惊呆了!原来软件开发根本不需要会编码
    c++day1
    Oracle【ORA-00600 internal error code arguments [2662]】恢复一例
  • 原文地址:https://blog.csdn.net/weixin_40294256/article/details/126338618