IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java 8之新特性详解 -> 正文阅读

[Java知识库]Java 8之新特性详解

1. Java8新特性简介

在这里插入图片描述

2. Java8新特性好处

  1. 速度更快
  2. 代码更少(增加了新特性Lambda表达式)
  3. 强大的Stream API
  4. 便于并行
  5. 最大化减少空指针异常:Optional
  6. Nashron引擎,允许在JVM上运行JS应用

3. Lambda表达式

3.1 Lambda表达式的使用

  1. 举例: ( o1, o2) -> Integer.compare(o1,o2);
  2. 格式:
    -> :lambda操作符 或箭头操作符
    ->左边:lambad形参列表,(其实就是接口中的抽象方法的形参列表)
    ->右边:lambda体 (其实就是重写的抽象方法的方法体)
  3. lambda表达式使用: (分6种情况)
    总结:->左边,lambda形参列表的参数类型可以省略(类型推断),
    如果lambda形参列表只有一个参数,其一对()小括号也可以省略
    如果有没有或这有2个以上的,就不要省了
    ->右边:lambda应该使用一对{}包裹,如果lambda体只有一条执行语句(可能是return语句)
    可以省略这一对{}和return关键字
  4. lambda表达式本质:作为函数式接口的实例
  5. 如果一个接口中,只声明了一个抽象方法,则此接口就成为函数式接口
  6. 所以以前用匿名实现类表示的,现在都可以用lambda表达式来写。

3.1.1 语法格式一:无参,无返回值

    // 语法格式一,无参,无返回值
    public static void test1(){
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("我爱北京故宫");
            }
        };
        r1.run();
        
        //Lambda
        Runnable r2 = () -> {System.out.println("我爱北京天安门");};
        r2.run();
    }

3.1.2 语法格式二:需要一个参数,但是没有返回值

    // 语法格式二,需要一个参数,但是没有返回值
    public static void test2(){
        Consumer<String> con = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con.accept("谎言和誓言区别是什么呢?");
        System.out.println("****************************");
        //Lambda
        Consumer<String> con2 = (String s) -> {
            System.out.println(s);
        };
        con2.accept("一个是听的人当真了,一个是说的人当真了");
    }

3.1.3 语法格式三:数据类型可以省略,因为可以由编译器推断得出,称为“类型推断”

   //语法格式三:数据类型可以省略,因为可以由编译器推断得出,称为“类型推断”
    public static void test3(){
        Consumer<String> con2 = (String s) -> {
            System.out.println(s);
        };
        con2.accept("一个是听的人当真了,一个是说的人当真了");

        Consumer<String> con3 = (s) -> {
            System.out.println(s);
        };
        con3.accept("一个是听的人当真了,一个是说的人当真了");
        //同样的效果
        ArrayList<String> list = new ArrayList<>();
        int [] arr = new int[]{1,2,3};
        int [] bb = {1,2,3};
    }

3.1.4 语法格式四:Lambda若只需要一个参数时,参数 的小括号可以省略

    //语法格式四:Lambda若只需要一个参数时,参数 的小括号可以省略
    public static void test4 (){
        Consumer<String> con3 = (s) -> {
            System.out.println(s);
        };
        con3.accept("一个是听的人当真了,一个是说的人当真了");


        Consumer<String> con4 = s -> {
            System.out.println(s);
        };
        con4.accept("一个是听的人当真了,一个是说的人当真了");

    }

3.1.5 语法格式五:Lambda需要两个或以上的参数,多条执行语句,并且有返回值

   //语法格式五:Lambda需要两个或以上的参数,多条执行语句,并且有返回值
    public static 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(com1.compare(11,12));
        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(11,12));
    }

3.1.6 语法格式六:当Lambda体只有一条语句时,return与大括号若有,都可以省略

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

        System.out.println(com2.compare(11,12));

        System.out.println("**************");
        Comparator<Integer> com3 = (o1,o2) -> o1.compareTo(o2);

        System.out.println(com3.compare(11,12));
    }

同样的,第四种可以省略大括号{}

    public static void test7(){
        Consumer<String> con4 = s -> {
            System.out.println(s);
        };
        con4.accept("一个是听的人当真了,一个是说的人当真了");

        System.out.println("**************");
        Consumer<String> con5 = s ->  System.out.println(s);
        con5.accept("一个是听的人当真了,一个是说的人当真了");
    }

4. Java内置的4大核心函数式接口

  1. Consummer 消费行接口,用途:对类型为T的对象应用操做,包含方法:void accept(T t)
    void accept(T t)
  2. Supplier 供给型接口,用途:返回类型为T的对象,包含方法:T get()
    T get()
  3. Function 函数式接口 用途:对类型为T的对象应用操作,并返回结果。结果是R
    R apply(T t) 类型的对象。包含方法:R apply(T t)
  4. Predicate 断定型接口 用途:确定类型为T的对象是否满足某约束,并返回boolean值。包含方法
    boolean test(T t) boolean test

4.1 Consummer 消费行接口

    public static void test1 (){
        happyTime(500, new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("学习太累了,去天上人间消费:" + aDouble);
            }
        });

        System.out.println("************************");

        happyTime(400,money -> System.out.println("消费:" + money));
    }
    public static void happyTime(double money, Consumer<Double> con){
        con.accept(money);
    }

4.2 Predicate 断定型接口

    public static void test2(){
        List<String> list = Arrays.asList("北京","南京","天津","普京");
        ArrayList<String>  filterStrs = filterString(list, new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.contains("京");
            }
        });
        System.out.println(filterStrs);
        //filterStrs.stream().forEach(System.out::println);
        System.out.println("****************************");

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

5. 方法引用的使用

  1. 使用情景:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用。
  2. 方法引用:本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以方法引用,也是函数式接口的实例。
  3. 使用格式:类(或者对象)::方法名
  4. 具体非为如下的三种情况:
    1.对象::非静态方法
    2.类::静态方法
    3.类::非静态方法
  5. 方法引用的使用要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的形参列表和返回值类型相同。针对1和2

5.1 情况一:对象::实例方法

    //
    //Consumer中的void accept(T t)
    //PrintStream中的void println(T t)
    public static void test1 (){
        Consumer<String> con1 = str -> System.out.println(str);
        con1.accept("北京");

        System.out.println("******************************");
        PrintStream ps = System.out;
        Consumer<String> con2 = ps::println;
        con2.accept("上海");
    }
    public static void test2(){
        Employee emp = new Employee(1000,"longxi",23,1000);
        Supplier<String> sup1 = () -> emp.getName();
        System.out.println(sup1.get());
        System.out.println("******************************");

        Supplier<String> sup2 = emp::getName;
        System.out.println(sup2.get());
    }

5.2 情况二:类::静态方法

    //情况二:类::静态方法
    //Comparator中的 int compare(T t1,T t2)
    //Integer中的 int compare(T t1,T t2)
    public  static  void test3(){
        Comparator<Integer> com1 = (t1,t2) ->Integer.compare(t1,t2);
        System.out.println(com1.compare(11,21));
        System.out.println("******************************");
        Comparator<Integer> com2 = Integer::compare;
        System.out.println(com2.compare(9,12));
    }
    public  static void  test4(){
        Function<Double, Long> func1 = new Function<Double, Long>() {
            @Override
            public Long apply(Double aDouble) {
                return Math.round(aDouble);
            }
        };
        System.out.println("******************************");
        Function<Double, Long> func2 = d -> Math.round(d);
        System.out.println(func2.apply(12.3));

        Function<Double, Long> func3 = Math::round;
        System.out.println(func3.apply(13.6));
    }

5.3 情况三:类::实例方法(有难度)

   // 情况三:类::实例方法(有难度)
    // Comparator中的 int compare(T t1,T t2)
    // String中的int t1.compareTo(t2)
    // 如果是2个参数,第1个参数是作为里面方法的调用者出现的,这种情况就可以用
    public static  void test5(){
        Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);
        System.out.println(com1.compare("abc","abd"));
        System.out.println("******************************");
        Comparator<String> com2 = String :: compareTo;
        System.out.println(com2.compare("abda","fdasfe"));
    }
    // BiPredicate中的boolean test(T t1,T t2)
    // String 中的boolean t1.equals(t2)
    public static  void test6(){
        BiPredicate<String,String> pre1 = (s1, s2)->s1.equals(s2);
        System.out.println(pre1.test("fasfe","fegege"));
        System.out.println("******************************");
        BiPredicate<String,String> pre2 = String ::equals;
        System.out.println(pre2.test("abc","abd"));
    }
    // Function 中的apply(T t1)
    // Employee 中的 String getName
    public static void test7(){
        System.out.println("************test7******************");
        Employee emp = new Employee(1000,"longxi",23,1000);

        Function<Employee,String> func1 = e -> e.getName();
        System.out.println(func1.apply(emp));
        System.out.println("******************************");
        Function<Employee,String> func2 = Employee :: getName;
        System.out.println(func2.apply(emp));
    }

6. 构造器引用

  • 和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。
  • 抽象方法的返回值类型即为构造器所属的类的类型

构造方法

    public Employee (){
        System.out.println("Employee()-------");
    }
   //构造器引用
    //Supplier中的get()
    //Employee的空参构造器:Employee()
    public static  void test1 (){
        Supplier<Employee> sup = new Supplier<Employee>() {
            @Override
            public Employee get() {
                return new Employee();
            }
        };
        System.out.println(sup.get());
        System.out.println("******************************");
        Supplier<Employee> sup1 = () -> new Employee();
        System.out.println(sup1.get());
        System.out.println("******************************");
        Supplier<Employee> sup2 = Employee::new;
        System.out.println(sup2.get());

    }
    // Function中的apply(T t)
    public static void test2(){
        Function<Integer,Employee> func1 = id -> new Employee(id);
        Employee apply = func1.apply(1000);
        System.out.println(apply);
        System.out.println("******************************");
        Function<Integer,Employee> func2 = Employee::new;
        Employee apply1 = func2.apply(1002);
        System.out.println(apply1);

    }
    // BiFunction中的apply(T t, U u )
    public static void test3(){
        BiFunction<Integer,String,Employee > func1 = (id,name) ->new Employee(id,name);
        System.out.println(func1.apply(1002,"longxi2"));
        System.out.println("******************************");
        BiFunction<Integer,String, Employee> func2 = Employee::new;
        System.out.println(func2.apply(1002,"longxi3"));
    }

7. 数组引用

可以把数组看成是一个特殊的类,则写法和构造引用一致。

    // 数组引用
    // Function中的apply(T t)
    public static void test4(){
        Function<Integer, String[]> func1 = Length -> new String[Length];
        System.out.println(Arrays.toString(func1.apply(5)));
        System.out.println("******************************");
        Function<Integer,String[]> func2 = String[]::new;
        System.out.println(Arrays.toString(func2.apply(10)));
    }

8. Stream API

Stream API提供了一种高效且易于使用的处理数据方式。
类似于使用SQL执行数据库查询。

8.1 为什么要使用Stream API

  • 实际开发中,项目中多数数据源都来自于Mysql,Oracle等。但现在数据源可以更多了,有MongDB,Redis等,而这些NoSql的数据就需要Java层面去做处理。
  • Stream 和Collection集合的区别:Collection是一种静态的内存数据结构,而Stream 是有关计算的。前者是主要面向内存,存储在内存中,后者主要是面向CPU,通过CPU实现计算。

8.2 什么是Stream

Stream 是数据渠道,用于操作数据源(集合,数组等)所生成的元素序列。
集合讲的数据,Stream讲的是计算

注意:

  1. Stream 自己不会存储元素。
  2. Stream 不会改变源对象,相反,他们会返回一个持有结果的新Stream
  3. Stream操作时延迟执行。这意味这他们会等到需要结果的时候才执行。

8.3 Stream操作的三个步骤

  1. 创建Stream
    一个数据源(如:集合、数组),获取一个流
  2. 中间操作
    一个中间操作链,对数据源进行处理
  3. 终止操作
    一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用。
    在这里插入图片描述

8.4 Stream的创建方式

8.4.1 创建Stream方式一:通过结合

    // 创建Stream方式一:通过结合
    public static void test1(){
        List<Employee> employees = EmployeeData.getEmployees();
        // 返回一个顺序流
        Stream<Employee> stream = employees.stream();
        // 返回一个并行流 多个线程
        Stream<Employee> employeeStream = employees.parallelStream();
    }

8.4.2 创建Stream方式二:通过数组

    // 创建Stream方式二:通过数组
    public static void test2(){
        int [] arr = new int[]{1,2,3,4};
        IntStream stream = Arrays.stream(arr);

        Employee employee = new Employee(1002, "longx");
        Employee employee2 = new Employee(1002, "longx2");
        Employee[] arr1 = new Employee[]{employee,employee2};
        Stream<Employee> stream1 = Arrays.stream(arr1);
    }

8.4.3 创建Stream方式三:Stream.of

    // 第三种方式 Stream.of
    public static void test3(){
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
    }

8.4.4 创建Stream方式四:创建无限流

    // 第四种方式 创建无限流
    public static void test4(){
        // 迭代
        Stream.iterate(0,t -> t+2).limit(10).forEach(System.out::println);
        // 生成
        Stream.generate(Math::random).limit(10).forEach(System.out::println);
    }

8.5 Stream 的中间操作

8.5.1 筛选与切片

在这里插入图片描述

    public static void test1(){
        //过滤
        List<Employee> list = EmployeeData.getEmployees();
        // 工资大于7000
        list.stream().filter(e ->e.getSalary() >7000).forEach(System.out::println);
        // 取前三条
        System.out.println();
        list.stream().limit(3).forEach(System.out::println);
        // 跳过前3条
        System.out.println();
        list.stream().skip(3).forEach(System.out::println);
        // 去重
        System.out.println();
        list.add(new Employee(1010,"刘强东",40, 8000));
        list.add(new Employee(1010,"刘强东",40, 8000));
        list.add(new Employee(1010,"刘强东",40, 8000));
        list.add(new Employee(1010,"刘强东",40, 8000));
        System.out.println(list);

        list.stream().distinct().forEach(System.out::println);

    }

8.5.2 映射

在这里插入图片描述

   //映射
    public static void test2(){
        //Map  相当与add 集合里套集合
        List<String> list = Arrays.asList("aa","bb","cc","dd");
        list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);

        //获取员工姓名长度大于3的员工姓名
        List<Employee> employees = EmployeeData.getEmployees();
        Stream<String> nameStream = employees.stream().map(e -> e.getName());
        nameStream.filter(name -> name.length() > 3).forEach(System.out::println);
        // 练习2
        Stream<Stream<Character>> streamStream = list.stream().map(StreamTest1::fromStringToStream);
        streamStream.forEach(s ->{
            s.forEach(System.out::println);
        });
        System.out.println("flatMap");
        //flatMap 相当于addAll,集合打散了
        Stream<Character> characterStream = list.stream().flatMap(StreamTest1::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();
    }

8.5.3 排序

在这里插入图片描述

    //排序
    public  static  void test4(){
        // sorted() 自然排序
        List<Integer> list = Arrays.asList(12, 45, 78, 32, -78, 797);
        list.stream().sorted().forEach(System.out::println);

        //会报异常,因为没有实现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)->Integer.compare(e1.getAge(),e2.getAge())).forEach(System.out::println);

        employees.stream().sorted((e1,e2)->{
            int value = Integer.compare(e1.getAge(),e2.getAge());
            if (value!= 0){
                return value;
            } else {
                return Double.compare(e1.getSalary(),e2.getSalary());
            }
        }).forEach(System.out::println);
    }

8.6 终止操作

8.6.1 匹配与查找

在这里插入图片描述

/**
 * @author LongXi
 * @create 2021-07-12 20:22
 */
public class StreamTest2 {
    public static void main(String[] args) {
        test1();
        test2();
    }
    // 匹配与查找
    public static void test1(){
        List<Employee> list = EmployeeData.getEmployees();

        // allMath
        //练习:是否所有员工年龄都大于18
        boolean allMatch = list.stream().allMatch(e -> e.getAge() > 18);
        System.out.println(allMatch);

        //anyMatch
        // 练习:是否存在员工工资大于10000
        boolean anyMatch = list.stream().anyMatch(e -> e.getSalary() > 10000);
        System.out.println(anyMatch);

        //noneMatch
        // 是否存在员工姓“雷”
        boolean noneMatch = list.stream().noneMatch(employee -> employee.getName().startsWith("雷"));
        System.out.println(noneMatch);

        //findFirst
        // 返回第一个元素
        Optional<Employee> first = list.stream().findFirst();
        System.out.println(first);

        //findAny
        // 返回当前流中任意一个元素
        //Optional<Employee> any = list.stream().findAny();
        Optional<Employee> any = list.stream().parallel().findAny();
        System.out.println(any);
    }
    public static void test2 (){
        List<Employee> list = EmployeeData.getEmployees();
        // count
        // 工资大于5000的员工个数
        long count = list.stream().filter(employee -> employee.getSalary() > 5000).count();
        System.out.println(count);

        //max
        // 返回最高的工资
        Optional<Double> max = list.stream().map(e -> e.getSalary()).max(Double::compare);
        System.out.println(max);

        //min
        // 返回工资最低的员工
        Optional<Employee> min = list.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
        System.out.println(min);

        //forEach - 内部迭代
        list.stream().forEach(System.out::println);
        //使用结合遍历
        list.forEach(System.out::println);

    }
}

8.6.2 规约

在这里插入图片描述

    public static void test3(){
        // reduce
        // 计算1-10的自然数的和
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        System.out.println(list.stream().reduce(0,Integer::sum));

        // 计算工资所有员工的工资总和
        List<Employee> list1 = EmployeeData.getEmployees();

        Stream<Double> rStream = list1.stream().map(Employee::getSalary);
        Optional<Double> reduce = rStream.reduce(Double::sum);

        //Optional<Double> reduce1 = rStream.reduce((e1,e2)->e1+e2);
        System.out.println(reduce);
        //System.out.println(reduce1);
    }

8.6.3 收集

在这里插入图片描述
在这里插入图片描述

        //collect
        //查找工资大于6000的员工,结果返回一个list或者set
        List<Employee> list = EmployeeData.getEmployees();
        List<Employee> employeeList = list.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
        employeeList.forEach(System.out::println);

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

9. Optional类

在这里插入图片描述
在这里插入图片描述
boy类

/**
 * @author LongXi
 * @create 2021-07-12 22:19
 */
public class Boy {
    private  Girl girl;

    @Override
    public String toString() {
        return "Boy{" +
                "girl=" + girl +
                '}';
    }

    public Girl getGirl() {
        return girl;
    }

    public void setGirl(Girl girl) {
        this.girl = girl;
    }

    public Boy(Girl girl) {
        this.girl = girl;
    }
}

girl类

/**
 * @author LongXi
 * @create 2021-07-12 22:19
 */
public class Girl {
    private  String name;

    public Girl() {

    }

    @Override
    public String toString() {
        return "Girl{" +
                "name='" + name + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Girl(String name) {
        this.name = name;
    }
}

测试类

    private  static void test1 (){
        // Optional.of 必须保证t是非空的
        Girl girl = new Girl();
        Optional.of(girl);


        //Optional.ofNullable 可以为空的
        girl = null;
        Optional<Girl> optionalGirl = Optional.ofNullable(girl);
        System.out.println(optionalGirl);
        
        // orElse
        Girl longxi = optionalGirl.orElse(new Girl("longxi"));
        System.out.println(longxi);
    }

测试结果
在这里插入图片描述

    // 以前写法
    public static  String getGirlName(Boy boy){
        return boy.getGirl().getName();
    }
    // 优化写法
    public static  String getGirlName1(Boy boy){
        if (boy != null){
            Girl girl = boy.getGirl();
            if (girl!= null){
                return  girl.getName();
            }
        }
        return null;
    }
    // 使用Optional优化写法
    public static  String getGirlName2(Boy boy){
        Optional<Boy> boy1 = Optional.ofNullable(boy);
        Boy boy2 = boy1.orElse(new Boy(new Girl("longxi1")));
        Girl girl = boy2.getGirl();

        Optional<Girl> girl1 = Optional.ofNullable(girl);

        Girl longxi2 = girl1.orElse(new Girl("longxi2"));
        return longxi2.getName();
    }
    private  static  void test3(){
        Boy boy = new Boy();
        String girlName = getGirlName1(boy);

        boy = null;
        String girlName2 = getGirlName2(boy);
        System.out.println(girlName2);

        boy = new Boy();
        girlName2 = getGirlName2(boy);
        System.out.println(girlName2);

        boy = new Boy(new Girl("longxi3"));
        girlName2 = getGirlName2(boy);
        System.out.println(girlName2);
    }

输出结果
在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-07-15 23:43:10  更:2021-07-15 23:43:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/5 8:20:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码