Java:Stream流

文章目录

以下代码使用JDK11编写。

1、体验Stream流

(1)案例需求

按照下面的要求完成集合的创建和遍历

  • 创建一个集合,存储多个字符串元素
  • 把集合中所有以"张"开头的元素存储到一个新的集合
  • 把"张"开头的集合中的长度为3的元素存储到一个新的集合
  • 遍历上一步得到的集合

(2)原始方式示例代码

java 复制代码
public class StreamDemo01 {
    public static void main(String[] args) {
        //集合的批量添加
        ArrayList<String> list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤"));
        //list.add()

        //遍历list1把以张开头的元素添加到list2中。
        ArrayList<String> list2 = new ArrayList<>();
        for (String s : list1) {
            if(s.startsWith("张")){
                list2.add(s);
            }
        }
        //遍历list2集合,把其中长度为3的元素,再添加到list3中。
        ArrayList<String> list3 = new ArrayList<>();
        for (String s : list2) {
            if(s.length() == 3){
                list3.add(s);
            }
        }
        for (String s : list3) {
            System.out.println(s);
        }      
    }
}

(3)使用Stream流示例代码

java 复制代码
public class StreamDemo01 {
    public static void main(String[] args) {
        //集合的批量添加
        ArrayList<String> list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤"));

        //Stream流
        list1.stream().filter(s->s.startsWith("张"))
                .filter(s->s.length() == 3)
                .forEach(s-> System.out.println(s));
    }
}

(4)Stream流的好处

  • 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印
  • Stream流把真正的函数式编程风格引入到Java中
  • 代码简洁
  • 结合了Lambda表达式,简化集合、数组的操作

2、Stream流的常见生成方式

(1)Stream流的思想

(2)Stream流的三类方法

  • 获取Stream流
    • 创建一条流水线,并把数据放到流水线上准备进行操作
  • 中间方法
    • 流水线上的操作
    • 一次操作完毕之后,还可以继续进行其他操作
  • 终结方法
    • 一个Stream流只能有一个终结方法
    • 是流水线上的最后一个操作

(3)生成Stream流的方式

  • Collection体系集合:使用默认方法stream()生成流, default Stream stream()

  • Map体系集合:把Map转成Set集合,间接的生成流

  • 数组:通过Arrays中的静态方法stream生成流

  • 同种数据类型的多个数据:通过Stream接口的静态方法of(T... values)生成流

(4)代码演示

java 复制代码
public class StreamDemo {
    public static void main(String[] args) {
        //Collection体系的集合可以使用默认方法stream()生成流
        List<String> list = new ArrayList<String>();
        Stream<String> listStream = list.stream();

        Set<String> set = new HashSet<String>();
        Stream<String> setStream = set.stream();

        //Map体系的集合间接的生成流
        Map<String,Integer> map = new HashMap<String, Integer>();
        Stream<String> keyStream = map.keySet().stream();
        Stream<Integer> valueStream = map.values().stream();
        Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();

        //数组可以通过Arrays中的静态方法stream生成流
        String[] strArray = {"hello","world","java"};
        Stream<String> strArrayStream = Arrays.stream(strArray);
      
      	//同种数据类型的多个数据可以通过Stream接口的静态方法of(T... values)生成流
        Stream<String> strArrayStream2 = Stream.of("hello", "world", "java");
        Stream<Integer> intStream = Stream.of(10, 20, 30);
    }
}

(5)详细操作

单列集合(Collection体系集合)

java 复制代码
public class StreamDemo02 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a","b","c","d","e");

        System.out.println("---------------一条语句:生成流并进行相关操作------------");
        list.stream()
                .forEach(s -> System.out.println(s));

        System.out.println("---------------把上面的一条语句进行拆分------------------");
        // 获取到一条流水线,并把集合中的数据放到流水线上
        Stream<String> stream1 = list.stream();
        // 使用终结方法打印一下流水线上的所有数据
        stream1.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                // s:依次表示流水线上的每一个数据
                System.out.println(s);
            }
        });
    }
}

双列集合(Map体系的集合间接的生成流)

java 复制代码
public class StreamDemo03 {
    public static void main(String[] args) {
        // 1.创建双列集合
        HashMap<String,Integer> hm = new HashMap<>();
        // 2.添加数据
        hm.put("aaa",111);
        hm.put("bbb",222);
        hm.put("ccc",333);
        hm.put("ddd",444);
        // 3.第一种获取stream流,只获取到了key
        hm.keySet().stream().forEach(s -> System.out.println(s));
        // 4.第二种获取stream流,可以获取到key和value
        hm.entrySet().stream().forEach(s-> System.out.println(s));
    }
}

数组(数组可以通过Arrays中的静态方法stream生成流)

java 复制代码
public class StreamDemo04 {
    public static void main(String[] args) {
        // 1.创建数组
        int[] arr1 = {1,2,3,4,5,6,7,8,9,10};
        String[] arr2 = {"a","b","c"};

        // 2.获取stream流
        Arrays.stream(arr1).forEach(s-> System.out.println(s));
        System.out.println("--------------------------------");
        Arrays.stream(arr2).forEach(s-> System.out.println(s));
        System.out.println("--------------------------------");


        /**
         * 注意:
         * Stream接口中静态方法of的细节:
         * 方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组
         * 但是数组必须是引用数据类型的,如果传递基本数据类型,是会把整个数组当做一个元素,放到Stream当中。
         */
        Stream.of(arr1).forEach(s-> System.out.println(s)); // 输出[I@17f6480

    }
}

一堆零散数据(同种数据类型的多个数据可以通过Stream接口的静态方法of(T... values)生成流)

java 复制代码
public class StreamDemo05 {
    public static void main(String[] args) {
        // 基本类型
        Stream.of(1,2,3,4,5).forEach(s-> System.out.println(s));
        // 引用类型
        Stream.of("a","b","c","d","e").forEach(s-> System.out.println(s));
    }
}

3、Stream流中间操作方法

注意1:如果是直接操作Stream流(如Stream.concat(stream1, stream2),而不是使用集合的stream格式,如list.stream()),中间方法返回的是新的Stream流,原来的Stream流只能使用一次。例如,用filter、limit、skip、concat、distinct、map等中间操作后,stream对象就无法再次被操作。建议使用链式编程或者把中间操作的结果存储到新的stream变量中再使用。

注意2:修改Stream流中的数据,不会影响原来集合或者数组中的数据

(1)概念:中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作

(2)常见方法

方法名 说明
Stream filter(Predicate predicate) 用于对流中的数据进行过滤
Stream limit(long maxSize) 返回此流中的元素组成的流,截取前指定参数个数的数据
Stream skip(long n) 跳过指定参数个数的数据,返回由该流的剩余元素组成的流
static Stream concat(Stream a, Stream b) 合并a和b两个流为一个流
Stream distinct() 返回由该流的不同元素(根据Object.equals(Object) )组成的流
Stream map(Function<T,R> mapper) 转换流中的数据类型

(3)filter代码演示

java 复制代码
public class StreamDemo06 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");

        // 1、把张开头且字符串长度为3的留下,其余数据过滤不要
        System.out.println("--------filter过滤:匿名内部类格式---------");
        list.stream()
                .filter(new Predicate<String>() {
                    @Override
                    public boolean test(String s) {
                        //如果返回值为true,表示当前数据留下
                        //如果返回值为false,表示当前数据舍弃不要
                        return s.startsWith("张")&&s.length()==3;

                    }
                })
                .forEach(s -> System.out.println(s));

        System.out.println("--------filter过滤:Lambda表达式格式---------");
        list.stream()
                .filter(s -> s.startsWith("张"))
                .filter(s -> s.length() == 3)
                .forEach(s -> System.out.println(s));

        System.out.println("--------filter过滤:Lambda表达式格式---------");
    }
}

(4)limit&skip代码演示

java 复制代码
public class StreamDemo06 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");
        
	    System.out.println("----limit获取前几个元素----");
        list.stream().limit(3).forEach(s -> System.out.println(s));
        System.out.println("----skip跳过前几个元素----");
        list.stream().skip(4) .forEach(s -> System.out.println(s));
 
        
        System.out.println("----练习:思路1----");
        /**
         * 课堂练习:获取 "张强", "张三丰", "张翠山"
         *
         * 第一种思路:先获取前面6个元素:"张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山",
         * 然后跳过前面3个元素
         */
        list.stream().limit(6).skip(3).forEach(s -> System.out.println(s));

        /**
         * 第二种思路:
         * 先跳过3个元素:"张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤"
         * 然后再获取前面3个元素:"张强", "张三丰", "张翠山"
         */
        System.out.println("----练习:思路2----");
        list.stream().skip(3).limit(3).forEach(s -> System.out.println(s));
    }
}

(5)concat&distinct代码演示

java 复制代码
public class StreamDemo07 {
    public static void main(String[] args) {
        ArrayList<String> list1 = new ArrayList<>();
        Collections.addAll(list1, "张无忌","张无忌","张无忌", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");

        ArrayList<String> list2 = new ArrayList<>();
        Collections.addAll(list2, "周芷若", "赵敏");


        System.out.println("----------------distinct元素去重---------");
        list1.stream().distinct().forEach(s -> System.out.println(s));
        System.out.println("----------------concat合并a和b两个流为一个流---------");
        Stream.concat(list1.stream(),list2.stream()).forEach(s -> System.out.println(s));
    }
}

(6)map代码演示

java 复制代码
public class StreamDemo08 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌-15", "周芷若-14", "赵敏-13", "张强-20", "张三丰-100", "张翠山-40", "张良-35", "王二麻子-37", "谢广坤-41");

        //需求:获取里面的年龄并进行打印
        System.out.println("--------map转换流中的数据类型:匿名内部类格式---------");
        /**
         * 第一个类型:流中原本的数据类型
         * 第二个类型:要转成之后的类型
         * apply的形参s:依次表示流里面的每一个数据,其返回值表示转换之后的数据
         * 当map方法执行完毕之后,流上的数据就变成了整数
         * 所以在下面forEach当中,s依次表示流里面的每一个数据,这个数据现在就是整数了
         */
        list.stream().map(new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                String[] arr = s.split("-");
                String ageString = arr[1];
                int age = Integer.parseInt(ageString);
                return age;
            }
        }).forEach(s-> System.out.println(s));

        System.out.println("--------map转换流中的数据类型:Lambda表达式格式---------");
        list.stream()
                .map(s ->Integer.parseInt(s.split("-")[1]))
                .forEach(s-> System.out.println(s));
    }
}

4、Stream流终结操作方法

(1)概念:终结操作的意思是执行完此方法之后,Stream流将不能再执行其他操作

(2)常见方法

方法名 说明
void forEach(Consumer action) 对此流的每个元素执行操作
long count() 返回此流中的元素数
toArray() 收集流中的数据,放到数组中
R collect(Collector collector) 收集流中的数据,放到集合中

(3)代码演示

forEach

java 复制代码
public class StreamDemo09 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");


        /**
         * void forEach(Consumer action)           遍历
         * Consumer的泛型:表示流中数据的类型
         * accept方法的形参s:依次表示流里面的每一个数据
         * 方法体:对每一个数据的处理操作(打印)
         */
        System.out.println("---------forEach:匿名内部类方式-----------");
        list.stream().forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
        System.out.println("---------forEach:Lambda表达式方式-----------");
        list.stream().forEach(s -> System.out.println(s));
    }
}

count

java 复制代码
public class StreamDemo09 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");
        
        // long count()统计
        System.out.println("---------count()统计-----------");
        long count = list.stream().count();
        System.out.println(count);

    }
}

5、Stream流的收集操作

(1)概念:对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中

(2)常用方法

方法名 说明
toArray() 收集流中的数据,放到数组中
R collect(Collector collector) 把结果收集到集合中

(3)工具类Collectors提供了具体的收集方式

方法名 说明
public static Collector toList() 把元素收集到List集合中
public static Collector toSet() 把元素收集到Set集合中
public static Collector toMap(Function keyMapper,Function valueMapper) 把元素收集到Map集合中

(4)收集到数组中

java 复制代码
public class StreamDemo10 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");

        // 需求:收集流中的数据,放到数组中-toArray()

        System.out.println("---------toArray():匿名内部类方式-----------");
        /**
         * IntFunction的泛型:具体类型的数组
         * apply的形参:流中数据的个数,要跟数组的长度保持一致
         * apply的返回值:具体类型的数组
         * 方法体:就是创建数组
         *
         * toArray方法的参数的作用:负责创建一个指定类型的数组
         * toArray方法的底层,会依次得到流里面的每一个数据,并把数据放到数组当中
         * toArray方法的返回值:是一个装着流里面所有数据的数组
         */
        String[] arr = list.stream().toArray(new IntFunction<String[]>() {
            @Override
            public String[] apply(int value) {
                return new String[value];
            }
        });
        System.out.println(Arrays.toString(arr));

        System.out.println("---------toArray():Lambda表达式方式-----------");
        String[] arr2 = list.stream().toArray(value -> new String[value]);
        System.out.println(Arrays.toString(arr2));
    }
}

(5)收集到集合中

注:如果要收集到Map集合当中,键不能重复,否则会报错

java 复制代码
package com.ya.mystream;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Stream流的收集操作:collect(Collector collector) 收集流中的数据,放到集合中 (List Set Map)
 */
public class StreamDemo11 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌-男-15", "周芷若-女-14", "赵敏-女-13", "张强-男-20",
                "张三丰-男-100", "张翠山-男-40", "张良-男-35", "王二麻子-男-37", "谢广坤-男-41");

        System.out.println("--------收集List集合当中-----------");
        //把所有的男性收集起来,放到List集合当中
        List<String> newList1 = list.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                .collect(Collectors.toList());
        System.out.println(newList1);

        System.out.println("--------收集Set集合当中-----------");
        //把所有的男性收集起来,放到Set集合当中
        Set<String> newList2 = list.stream().filter(s -> "男".equals(s.split("-")[1]))
                .collect(Collectors.toSet());
        System.out.println(newList2);


        System.out.println("--------收集Map集合当中:匿名内部类方式-----------");
        /**
         * 把所有的男性收集起来,放到Map集合当中
         * 键:姓名。 值:年龄
         */
        Map<String, Integer> map = list.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                /*
                 *   toMap : 参数一表示键的生成规则
                 *           参数二表示值的生成规则
                 *
                 * 参数一:
                 *       Function泛型一:表示流中每一个数据的类型
                 *               泛型二:表示Map集合中键的数据类型
                 *
                 *        方法apply形参:依次表示流里面的每一个数据
                 *               方法体:生成键的代码
                 *               返回值:已经生成的键
                 *
                 *
                 * 参数二:
                 *        Function泛型一:表示流中每一个数据的类型
                 *                泛型二:表示Map集合中值的数据类型
                 *
                 *       方法apply形参:依次表示流里面的每一个数据
                 *               方法体:生成值的代码
                 *               返回值:已经生成的值
                 *
                 * */
                .collect(Collectors.toMap(
                        // key
                        new Function<String, String>() {
                            @Override
                            public String apply(String s) {
                                //张无忌-男-15
                                return s.split("-")[0];
                            }
                        },
                        // value
                        new Function<String, Integer>() {
                            @Override
                            public Integer apply(String s) {
                                return Integer.parseInt(s.split("-")[2]);
                            }
                        }));
        System.out.println(map);

        System.out.println("--------收集Map集合当中:Lambda表达式方式-----------");
        Map<String, Integer> map2 = list.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                .collect(Collectors.toMap(
                        // key
                        s -> s.split("-")[0],
                        // value
                        s -> Integer.parseInt(s.split("-")[2])));

        System.out.println(map2);
    }
}

6、Stream流综合练习

6.1 练习1

  • 案例需求
    • 定义一个集合,并添加一些整数 1,2,3,4,5,6,7,8,9,10
    • 过滤奇数,只留下偶数
    • 并将结果保存起来
java 复制代码
public class Test1 {
    public static void main(String[] args) {

        //1. 定义一个集合
        ArrayList<Integer> list = new ArrayList<>();
        //2.添加一些整数
        Collections.addAll(list, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        //3.过滤奇数,只留下偶数
        //进行判断,如果是偶数,返回true 保留
        List<Integer> newList = list.stream()
                .filter(n -> n % 2 == 0)
                .collect(Collectors.toList());
        //4.打印集合
        System.out.println(newList);
    }
}

6.2 练习2

  • 案例需求
    • 创建一个ArrayList集合,并添加以下字符串,字符串中前面是姓名,后面是年龄
      "zhangsan,23"
      "lisi,24"
      "wangwu,25"
    • 保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值。
java 复制代码
public class Test2 {
    public static void main(String[] args) {

        //1.创建一个ArrayList集合
        ArrayList<String> list = new ArrayList<>();
        //2.添加以下字符串
        list.add("zhangsan,23");
        list.add("lisi,24");
        list.add("wangwu,25");
        //3.保留年龄大于等于24岁的人
        System.out.println("--------收集为Map集合:匿名内部类方式--------");
        Map<String, Integer> map = list.stream()
                .filter(s -> Integer.parseInt(s.split(",")[1]) >= 24)
                .collect(Collectors.toMap(
                        // key
                        new Function<String, String>() {
                            @Override
                            public String apply(String s) {
                                return s.split(",")[0];
                            }
                        },
                        // value
                        new Function<String, Integer>() {
                            @Override
                            public Integer apply(String s) {
                                return Integer.parseInt(s.split(",")[1]);
                            }
                        }));
        System.out.println(map);

        
        System.out.println("--------收集为Map集合:Lambda表达式方式--------");
        Map<String, Integer> map1 = list.stream()
                .filter(s -> Integer.parseInt(s.split(",")[1]) >= 24)
                .collect(Collectors.toMap(
                        // key
                        s -> s.split(",")[0],
                        // value
                        s -> Integer.parseInt(s.split(",")[1])));

        System.out.println(map1);
    }
}

6.3 练习3

  • 案例需求

    现在有两个ArrayList集合,分别存储6名男演员的名字和年龄以及6名女演员的名字和年龄。
    姓名和年龄中间用逗号隔开。
    比如:张三,23
    要求完成如下的操作:
    1,男演员只要名字为3个字的前两人
    2,女演员只要姓杨的,并且不要第一个
    3,把过滤后的男演员姓名和女演员姓名合并到一起
    4,将上一步的演员信息封装成Actor对象。
    5,将所有的演员对象都保存到List集合中。
    备注:演员类Actor,属性有:name,age
    男演员:  "蔡坤坤,24" , "叶齁咸,23", "刘不甜,22", "吴签,24", "谷嘉,30", "肖梁梁,27"
    女演员:  "赵小颖,35" , "杨颖,36", "高元元,43", "张天天,31", "刘诗,35", "杨小幂,33"
    
  • 代码实现

    演员类

    java 复制代码
    public class Actor {
        private String name;
        private int age;
    
        public Actor() {
        }
        
        public Actor(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        /**
         * 获取
         * @return name
         */
      public String getName() {
            return name;
      }
    
        /**
         * 设置
         * @param name
         */
        public void setName(String name) {
            this.name = name;
        }
    
        /**
         * 获取
         * @return age
         */
        public int getAge() {
            return age;
        }
    
        /**
         * 设置
         * @param age
         */
        public void setAge(int age) {
            this.age = age;
        }
    
        public String toString() {
            return "Actor{name = " + name + ", age = " + age + "}";
        }
    }

    测试类

    java 复制代码
    public class Test3 {
        public static void main(String[] args) {
    
            //1.创建两个ArrayList集合
            ArrayList<String> manList = new ArrayList<>();
            ArrayList<String> womenList = new ArrayList<>();
            //2.添加数据
            Collections.addAll(manList, "蔡坤坤,24", "叶齁咸,23", "刘不甜,22", "吴签,24", "谷嘉,30", "肖梁梁,27");
            Collections.addAll(womenList, "赵小颖,35", "杨颖,36", "高元元,43", "张天天,31", "刘诗,35", "杨小幂,33");
            //3.男演员只要名字为3个字的前两人
            Stream<String> stream1 = manList.stream()
                    .filter(s -> s.split(",")[0].length() == 3)
                    .limit(2);
            //4.女演员只要姓杨的,并且不要第一个
            Stream<String> stream2 = womenList.stream()
                    .filter(s -> s.split(",")[0].startsWith("杨"))
                    .skip(1);
            
            //5.把过滤后的男演员姓名和女演员姓名合并到一起
            //演员信息封装成Actor对象,String -> Actor对象 (类型转换,使用map中间操作方法)
    
            
            // 注意:这里只能使用一个方式,两个方式同时打开运行会报错"IllegalStateException: stream has already been operated upon or closed"
            // 因为stream1, stream2已经被操作过了,不是原来的stream1, stream2了
            /*System.out.println("-------------匿名内部类方式--------------");
            List<Actor> list = Stream.concat(stream1, stream2).map(new Function<String, Actor>() {
                @Override
                public Actor apply(String s) {
                    String name = s.split(",")[0];
                    int age = Integer.parseInt(s.split(",")[1]);
                    return new Actor(name, age);
                }
            }).collect(Collectors.toList());
            System.out.println(list);*/
    
            
            System.out.println("-------------Lambda表达式方式--------------");
    
            List<Actor> list1 = Stream.concat(stream1, stream2)
                    .map(s -> new Actor(s.split(",")[0], Integer.parseInt(s.split(",")[1])))
                    .collect(Collectors.toList());
            System.out.println(list1);
        }
    }
相关推荐
morris1312 分钟前
【SpringBoot】Xss的常见攻击方式与防御手段
java·spring boot·xss·csp
七星静香27 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员28 分钟前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU28 分钟前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea
stewie631 分钟前
在IDEA中使用Git
java·git
Elaine2023911 小时前
06 网络编程基础
java·网络
G丶AEOM1 小时前
分布式——BASE理论
java·分布式·八股
落落鱼20131 小时前
tp接口 入口文件 500 错误原因
java·开发语言
想要打 Acm 的小周同学呀1 小时前
LRU缓存算法
java·算法·缓存
镰刀出海1 小时前
Recyclerview缓存原理
java·开发语言·缓存·recyclerview·android面试