Java 7、Java 8常用新特性

news2024/11/18 5:43:29

目录

  • Java 8 常用新特性
    • 1、Lambda 表达式
    • 2、方法引用
      • 2.1 静态方法引用
      • 2.2 特定对象的实例方法引用
      • 2.3 特定类型的任意对象的实例方法引用
      • 2.4 构造器引用
    • 3、接口中的默认方法
    • 4、函数式接口
      • 4.1 自定义函数式接口
      • 4.2 内置函数式接口
    • 5、Date/Time API
    • 6、Optional 容器类型
    • 7、Stream API
      • 7.1 Streams流
      • 7.2 Collectors收集器
      • 7.3 Parallel Streams(扩展)
  • Java 7 常用新特性(补充)
    • 1、二进制字面量
    • 2、数字字面量下划线支持
    • 3、switch中使用String
    • 4、对集合类的语言支持
      • 4.1 泛型实例创建的简化
      • 4.2 "diamond"操作符
    • 5、自动资源管理
    • 6、try-catch多异常捕获
    • 7、文件流
      • 7.1 文件路径(Path)
      • 7.2 文件属性(FileAttribute)
      • 7.3 文件I/O
        • 检查文件路径是否存在
        • 创建目录
        • 读取文件
        • 写入文件
        • 复制文件
        • 移动文件
        • 删除文件
      • 7.4 异步文件I/O
      • 7.5 文件遍历
        • Files.walk方法
        • Files.walkFileTree方法

Java 8 常用新特性

1、Lambda 表达式

Java 8 引入了 Lambda 表达式,这是一种新的函数式编程特性,允许你以简洁的方式表示匿名函数。Lambda 表达式特别适用于那些需要简短函数作为参数的场景,比如 Java 8 中的 Stream API。
Lambda 表达式的基本语法如下:

(parameter-list) -> { function-body }

其中,parameter-list 是输入参数列表,-> 是 Lambda 符号,function-body 是 Lambda 体的代码。


2、方法引用

在Java 8中,方法引用是一个简洁的方式来表示Lambda表达式。它允许你直接引用已存在的方法、构造器或实例方法,而不是创建一个匿名类。使用方法引用可以使代码更加简洁易读,特别是当你需要传递一个函数作为参数时(例如在Stream API中)。方法引用主要有四种类型:

2.1 静态方法引用

使用类名引用一个静态方法。

        List<String> list = new ArrayList<>();
        list.add("d");
        list.add("b");
        list.add("c");

        list.sort(String::compareToIgnoreCase);// 比较ascll码
        System.out.println(list);

2.2 特定对象的实例方法引用

使用特定对象的引用来调用其实例方法。

        String l="hello world";
        Predicate<String> predicate = l::endsWith; // 从尾部开始比较
        boolean b = predicate.test("ld");
        System.out.println(b);

2.3 特定类型的任意对象的实例方法引用

可以用于引用特定类型的任意对象的实例方法。

        List<String> list = new ArrayList<>();
        list.add("d");
        list.add("b");
        list.add("c");
        
        List<String> collect = list.stream()
                .filter(String::isEmpty) // false
                .collect(Collectors.toList());
        System.out.println(collect); // []

2.4 构造器引用

用于引用类的构造器。

        Supplier<String> supplier1=String::new;
        Supplier<List<String>> supplier2=ArrayList::new;
        Supplier<Map<String,String>> supplier3=HashMap::new;
        supplier1.get();
        supplier2.get();
        supplier3.get();

3、接口中的默认方法

在Java 8中,接口引入了默认方法(Default Methods)的概念。默认方法允许我们在接口中定义实现的方法,而不需要子类必须实现它们。这提供了一种方式,允许我们在不破坏与现有代码的兼容性的情况下,向接口添加新方法。默认方法允许我们逐步演进接口,同时保持与旧代码库的兼容性。默认方法使用default关键字进行标记。以下是一个简单示例:

public interface MyInterface {

    // 抽象方法
    void abstractMethod();

    // 默认方法
    default void defaultMethod() {
        System.out.println("调用默认方法");
    }

    // 静态方法
    static void staticMethod() {
        System.out.println("调用静态方法");
    }
}
@Service
public class MyInterfaceImpl implements MyInterface {

    @Override
    public void abstractMethod() {
        System.out.println("重写抽象方法");
    }
}
        MyInterfaceImpl myInterface = new MyInterfaceImpl();
        myInterface.abstractMethod();
        myInterface.defaultMethod();

        MyInterface.staticMethod();

4、函数式接口

在Java 8中,函数式接口(Functional Interface)是一个只有一个抽象方法的接口。由于Lambda表达式的引入,函数式接口变得特别有用,因为Lambda表达式可以被用来简洁地表示这些接口的实现。函数式接口是Java实现函数式编程特性的基础。

4.1 自定义函数式接口

Lambda 表达式经常与函数式接口一起使用。定义一个无实现类的接口,接口方法有且只有一个

@FunctionalInterface
public interface MyService {
    void myMethod(String l);
}

MyService myService=(s)-> System.out.println(s);
//或
MyService myService=(s)-> {
	System.out.println(s);
};

myService.myMethod("这是一个自定义的函数式接口");


/* 等价写法 */
public interface MyService {
	void myMethod(String l);
}

public class MyServiceImpl implements MyService {
    @Override
    public void myMethod(String l) {
        System.out.println(l);
    }	
}

myService.myMethod("这是一个字符串");

4.2 内置函数式接口

Java 8 中添加了很多内置的函数式接口,比如 Runnable, Callable, Comparator, Predicate 等,路径在java.util.function包中。
在这里插入图片描述


类型参数定义及示例:

  • < T > 参数输入类型
  • < U > 第二个参数输入类型
  • < R > 参数输出类型

Predicate< T > 接口

        Predicate<Integer> predicate = s -> s>6;
        boolean result = predicate.test(7); // true
        System.out.println(result);

Function<T, R>接口

        Function<Integer, Integer> function = s -> s * s;
        Integer result = function.apply(6); // 36
        System.out.println(result);

BiFunction<T, U, R> 接口

        BiFunction<Integer,Integer,String> biFunction = (x,y)->{
            Integer z=x*y;
          return "计算结果为:"+z;
        };
        String result =biFunction.apply(3,6);
        System.out.println(result); // 计算结果为:18

5、Date/Time API

Java 8引入了全新的Date/Time API,它提供了更简洁、易读和强大的日期时间处理能力。这个新的API是线程安全的,并且是不可变的,这意味着每次对日期时间的修改都会返回一个新的对象,而原始对象则保持不变,路径在java.time包中。以下是Java 8 Date/Time API的一些主要类和接口:

方法说明默认输出格式
LocalDate表示没有时区的日期2024-03-27
LocalTime表示没有时区的时间17:00:23.741
LocalDateTime表示包含日期和时间的日期时间,没有时区2024-03-27T17:00:23.741
ZonedDateTime表示包含日期、时间、时区的日期时间2024-03-27T17:00:23.742+08:00[GMT+08:00]
OffsetTime表示带有时区偏移的时间17:00:23.742+08:00
OffsetDateTime表示带有时区偏移的日期时间2024-03-27T17:00:23.743+08:00
Period表示年、月、日之间的时间段P2024Y1M1D
Duration表示时间量,通常以秒和纳秒为单位PT60H
TemporalAdjuster用于调整日期和时间的接口/
ChronoUnit枚举类型,表示时间单位,如天、小时、分钟等/
ZoneId表示时区ID的类/
ZoneOffset表示时区偏移的类/
DateTimeFormatter格式化日期时间/

一些常用方法示例:

        //表示没有时区的日期
        LocalDate localDate1 =LocalDate.now();
        LocalDate localDate2 =LocalDate.of(2024, 1,1);
        System.out.println(
                "当前日期:"+localDate1.toString()+"\n"+
                "设置规定日期:"+localDate2.toString()
        );


        //格式化日期
        DateTimeFormatter dateTimeFormatter1 =DateTimeFormatter.ofPattern("yyyy/MM/dd");
        String format1 = localDate1.format(dateTimeFormatter1);
        String format2 = localDate1.format(DateTimeFormatter.ISO_DATE);
        System.out.println(
                "自定义日期格式:"+format1+"\n"+
                "内置日期格式:"+format2
        );

        //解析字符串为日期
        LocalDate parse1 = LocalDate.parse("2024-01-01");
        LocalTime parse2 = LocalTime.parse("12:00:00",DateTimeFormatter.ISO_TIME);
        System.out.println(parse1+"\n"+parse2);


        //表示没有时区的时间
        LocalTime localTime1 =LocalTime.now();
        LocalTime localTime2 =LocalTime.of(10,0,0);
        System.out.println(
                "当前时间:"+localTime1.toString()+"\n"+
                "设置规定时间:"+localTime2.toString()
        );

        //格式化时间
        DateTimeFormatter dateTimeFormatter2 =DateTimeFormatter.ofPattern("HH点mm分ss秒");
        String format3 = localTime1.format(dateTimeFormatter2);
        String format4 = localTime1.format(DateTimeFormatter.ISO_TIME);
        System.out.println(
                "自定义时间格式:"+format3+"\n"+
                "内置时间格式:"+format4
        );


        //表示包含日期和时间的日期时间,没有时区
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDateTime);

        //格式化时间日期
        DateTimeFormatter dateTimeFormatter3 =DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        String format5 = localDateTime.format(dateTimeFormatter3);
        String format6 = localDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
        System.out.println(
                "自定义时间日期格式:"+format5+"\n"+
                "内置时间日期格式:"+format6
        );

        //表示包含日期、时间、时区的日期时间
        ZonedDateTime zonedDateTime =ZonedDateTime.now();
        System.out.println(zonedDateTime);

        //表示带有时区偏移的时间
        OffsetTime offsetTime =OffsetTime.now();
        System.out.println(offsetTime);

        //表示带有时区偏移的日期时间
        OffsetDateTime offsetDateTime =OffsetDateTime.now();
        System.out.println(offsetDateTime);

        //表示年、月、日之间的时间段
        Period period =Period.of(2024,1,1);
        System.out.println(period.toString());

        //表示时间量,通常以秒和纳秒为单位
        Duration duration=Duration.of(60, ChronoUnit.HOURS);
        System.out.println(duration);

        //用于调整日期和时间的接口
        TemporalAdjuster temporalAdjuster =(s)->{
            return s;
        };
        LocalDate localDate = localDate1.plusDays(1);
        Temporal temporal = temporalAdjuster.adjustInto(localDate);
        System.out.println(temporal.toString());

        //枚举类型,表示时间单位,如天、小时、分钟等
        ChronoUnit chronoUnit=ChronoUnit.DAYS;
        System.out.println(chronoUnit.toString());

        //表示时区ID的类
        ZoneId zoneId=ZoneId.of("GMT+08:00");
        System.out.println(zoneId.toString());

        //表示时区偏移的类
        ZoneOffset zoneOffset =ZoneOffset.of("+08:00");
        System.out.println(zoneOffset.toString());

6、Optional 容器类型

Optional 是 Java 8 引入的一个容器对象,用于表示某个值存在或不存在,而不是传统的 null 值。Optional 提供了一种更优雅和类型安全的方式来处理可能为 null 的值,从而避免了 NullPointerException。当你有一个值可能是 null,并且你想以更清晰、更简洁的方式处理这种情况时,Optional 就非常有用。使用 Optional 可以使你的代码更易于阅读和维护,同时减少处理 null 值时的错误。

/* 示例 */
        // 使用 of 方法创建一个包含值的 Optional
        Optional<String> optional1 = Optional.of("hello world");

        // 使用 ofNullable 方法创建一个可能包含 null 的 Optional
        Optional<String> optional2 = Optional.ofNullable(null);

        // 创建一个空的 Optional
        Optional<String> optional3 = Optional.empty();

        System.out.println(
                "optional1的值:"+optional1+"\n"+
                "optional2的值:"+optional2+"\n"+
                "optional3的值:"+optional3
        );
		/* 常用方法 */
		// isPresent() 检查值是否存在
        boolean present = optional1.isPresent(); //true
        System.out.println(present);

        // ifPresent() 如果值存在则执行给定的操作
        optional1.ifPresent(s->{
            System.out.println("打印:"+s); //打印:hello world
        });

        // get() 获取值,如果 Optional 为空则抛出 NoSuchElementException
        String s1 = optional1.get();

        // orElse() 如果值存在则返回它,否则返回提供的默认值
        String s2 = optional2.orElse("optional2值为空");

        // orElseGet() 如果值存在则返回它,否则使用提供的 Supplier 生成默认值
        String s3 = optional3.orElseGet(() -> {
            return "optional3值为空";
        });

        System.out.println(
                "s1:"+s1+"\n"+
                "s2:"+s2+"\n"+
                "s3:"+s3
        );

        // map() 如果值存在则应用函数并返回新的 Optional,不存在则不执行map()
        Optional<Integer> optional4 = optional1.map(String::length);
        Optional<Integer> optional5 = optional2.map(String::length);
        System.out.println(
                "optional4:"+optional4.orElse(-1)+"\n"+
                "optional5:"+optional5.orElse(-1)
        );

        // flatMap() 如果值存在则应用函数并返回结果的 Optional,否则返回空的 Optional
        Optional<String> optional6 = optional1.flatMap(s -> {
            return Optional.ofNullable("获取optional1的值:" + s);
        });
        Optional<String> optional7 = optional2.flatMap(s -> {
            return Optional.ofNullable("获取optional2的值:" + s);
        });
        System.out.println(
                "optional6:"+optional6.orElse(null)+"\n"+
                "optional7:"+optional7.orElse(null)
        );

7、Stream API

7.1 Streams流

在Java 8及更高版本中,Stream API 提供了一种新的、函数式的方法来处理集合(如 List、Set 等)。使用 Stream API,你可以轻松地对集合进行各种操作,如过滤、映射、排序、聚合等,而无需显式地编写循环。

方法简要说明
forEach(Consumer action)遍历元素,执行指定的操作
peek(Consumer action)遍历元素,插入节点调试,不影响原本操作
distinct()去除重复元素
sorted()升序排序
count()计数
filter(Predicate predicate)过滤出所有符合条件的元素 相当于if
map(Function mapper)将元素转换为特定类型
flatMap(Function mapper)嵌套map
IntStream.sum()聚合元素
boxed()将基本数据类型转换为对应的包装类类型
limit(long maxSize)限制元素数量,设定集合容量
skip(long n)跳过前N个元素
findFirst()返回第一个元素
findAny()返回任意一个元素
reduce(BinaryOperator accumulator)将所有元素归成一个约定的结果
collect(Collector collector)收集结果到一个集合中
allMatch(Predicate predicate)判断是否所有元素符合给定条件
anyMatch(Predicate predicate)判断是否有元素符合给定条件
noneMatch(Predicate predicate)判断是否所有元素都不符合给定条件
/* 示例 */
        // forEach 遍历元素,执行指定的操作
        List<String> list1 = Arrays.asList("a", "b", "c");
        list1.stream().forEach(s-> System.out.println(s));
        list1.stream().forEach(System.out::println);

        //peek 遍历元素,插入节点调试,不影响原本操作
        List<Integer> list = Arrays.asList(1,2,3,4,5);
        List<Integer> collect = list.stream()
                .filter(s->s>2)
                .peek(s -> System.out.println("输出:"+s))
                .collect(Collectors.toList());

        // distinct 去除重复元素
        List<Integer> list2 = Arrays.asList(1, 2, 1, 3);
        List<Integer> collect2 = list2.stream().distinct().collect(Collectors.toList());
        System.out.println(collect2);

        // sorted 升序排序
        List<String> list3 = Arrays.asList("a", "l", "c","j");
        List<String> collect3 = list3.stream().sorted().collect(Collectors.toList());
        System.out.println(collect3);

        // count 计数
        long count = list3.stream().count();
        System.out.println(count);

        // filter 过滤出所有符合条件的元素 相当于if
        List<Integer> list4 = Arrays.asList(9, 8, 7, 6);
        List<Integer> collect4 = list4.stream().filter(s -> s > 6).collect(Collectors.toList());
        System.out.println(collect4);

        // map 将元素转换为特定类型
        List<Integer> list5 = Arrays.asList(1,2,3,4,5);
        List<String> collect5 = list5.stream().map(s -> {
            return "计算结果为:"+s*s;
        }).collect(Collectors.toList());
        System.out.println(collect5);

        // flatMap 嵌套map
        List<Integer> collect6 = list5.stream().flatMap(s -> {
            return list5.stream().filter(a -> a > 4);
        }).collect(Collectors.toList());
        System.out.println(collect6);

        //sum 聚合元素
        int sum = list5.stream().mapToInt(s -> s * 2).sum();
        System.out.println("sum:" + sum);

        // boxed 将基本数据类型转换为对应的包装类类型
        int [] a ={1,2,3,4,5};
        List<Integer> collect7 = Arrays.stream(a).boxed().collect(Collectors.toList());
        System.out.println(collect7);

        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        IntStream intStream = numbers.stream().mapToInt(i -> i);  //转成IntStream
        Stream<Integer> boxed = intStream.boxed();                //转成Stream<Integer>
        List<Integer> collect8 = boxed.collect(Collectors.toList());
        System.out.println(collect8);


        //limit 限制元素数量,设定集合容量
        List<Integer> list9 = Arrays.asList(1,2,3,4,5);
        List<Integer> collect9 = list9.stream().limit(2).collect(Collectors.toList());
        System.out.println(collect9);

        //skip 跳过前N个元素
        List<Integer> list10 = Arrays.asList(1,2,3,4,5);
        List<Integer> collect10 = list10.stream().skip(3).collect(Collectors.toList());
        System.out.println(collect10);

        //findFirst() 返回第一个元素,findAny() 返回任意一个元素
        List<Integer> list11 = Arrays.asList(1,2,3,4,5);
        Optional<Integer> first = list11.stream().findFirst();
        Optional<Integer> any = list11.stream().findAny();
        System.out.println(
                "返回第一个元素:"+first.toString()+"\n"+
                "返回任意一个元素:"+any.toString()
        );

        /* 将所有元素归成一个约定的结果 */
        List<Integer> list1 = Arrays.asList(1,2,3,4,5);
        Integer reduce1 = list1.stream().reduce(0, (x, y) -> x + y);
        System.out.println(reduce1);

        List<String > list2 = Arrays.asList("a","b","c");
        Optional<String> reduce2 = list2.stream().reduce((x, y) -> x + y);
        System.out.println(reduce2.toString());

        List<Integer> list3 = Arrays.asList(1,2,3,4,5);
        BinaryOperator<Integer> binaryOperator = (x, y)->x*y;
        Integer reduce3 = list3.stream().reduce(1,binaryOperator, binaryOperator);
        System.out.println(reduce3);
        List<Integer> list = Arrays.asList(1,2,3,4,5);

        //allMatch 判断是否所有元素符合给定条件
        Predicate<Integer> predicate1 = s -> s>0;
        boolean b1 = list.stream().allMatch(predicate1);
        System.out.println("判断是否所有元素符合给定条件: "+b1);

        //anyMatch 判断是否有元素符合给定条件
        Predicate<Integer> predicate2 = s -> s>4;
        boolean b2 = list.stream().anyMatch(predicate2);
        System.out.println("判断是否有元素符合给定条件: "+b2);

        //noneMatch 判断是否所有元素都不符合给定条件
        Predicate<Integer> predicate3 = s -> s>10;
        boolean b3 = list.stream().noneMatch(predicate3);
        System.out.println("判断是否所有元素都不符合给定条件: "+b3);

7.2 Collectors收集器

在Java 8中,Collectors是一个静态工具类,它提供了许多有用的收集器(Collector)实现,用于支持在流(Stream)上的各种聚合操作。这些收集器可以用于收集流中的元素,并生成一个汇总结果或一个汇总结果的集合。以下是一些常用的Collectors收集器方法:

方法简要说明
toList()将流中的元素收集到一个List中
toSet()将流中的元素收集到一个Set中,去除重复项
toCollection(Supplier collectionFactory)将流中的元素收集到指定的集合类型中
toMap(Function keyMapper,Function valueMapper,BinaryOperator mergeFunction)将流中的元素收集到一个Map中
counting()计算流中元素的数量
summingInt(ToIntFunction mapper)对流中元素的某个属性进行求和,针对不同类型有不同方法,如:summingDouble,summingLong
averagingInt(ToIntFunction mapper)计算流中元素的某个属性的平均值,针对不同类型有不同方法,如:averagingDouble,averagingLong
maxBy(Comparator comparator)根据指定比较器找到流中最大的元素
minBy(Comparator comparator)根据指定比较器找到流中最小的元素
joining(CharSequence delimiter)将流中的元素连接成一个字符串,可以使用指定的分隔符
groupingBy(Function classifier)根据分类函数对流中的元素进行分组
reducing(BinaryOperator op)对流中的元素进行规定约定的操作
mapping(Function mapper,Collector downstream)对流中的元素应用映射函数,并对结果进行收集
collectingAndThen(Collector downstream,Function finisher)包裹另一个收集器,对其结果进行二次处理
/* 示例 */
        //toList 将流中的元素收集到一个List中
        List<Integer> list1 = Arrays.asList(1,2,3,4,5);
        List<Integer> collect1 = list1.stream()
                .filter(s->s>3)
                .collect(Collectors.toList());
        System.out.println(collect1);

        //toSet 将流中的元素收集到一个Set中,去除重复项
        List<Integer> list2 = Arrays.asList(1,2,3,4,5,3);
        Set<Integer> collect2 = list2.stream().collect(Collectors.toSet());
        System.out.println(collect2);

        //toCollection 将流中的元素收集到指定的集合类型中
        List<Integer> list3 = Arrays.asList(1,2,3,4,5,3);
        HashSet<Integer> collect3 = list3.stream().collect(Collectors.toCollection(HashSet::new));
        System.out.println(collect3);

        //toMap 将流中的元素收集到一个Map中
        List<Person> list4 = Arrays.asList(
                new Person("L", 1, 18),
                new Person("J", 2, 18),
                new Person("A", 1, 30),
                new Person("A", 1, 20)
        );

        //key不鞥重复,针对有重复的情况需要处理 ------ (t,u)->u:当两个key相同时怎么处理
        Map<String, Integer> collect4 = list4.stream()
                .collect(Collectors.toMap(Person::getName, Person::getAge, (t, u) -> u));
        System.out.println(collect4);

        //counting 计算流中元素的数量
        List<Integer> list5 = Arrays.asList(1,2,3,4,5);
        Long collect5 = list5.stream().collect(Collectors.counting());
        System.out.println(collect5);

        //summingInt 对流中元素的某个属性进行求和,针对不同类型有不同方法,如:summingDouble,summingLong
        List<Integer> list6 = Arrays.asList(1,2,3,4,5);
        Integer collect6 = list6.stream().collect(Collectors.summingInt(Integer::intValue));
        System.out.println(collect6);

        //averagingInt 计算流中元素的某个属性的平均值,针对不同类型有不同方法,如:averagingDouble,averagingLong
        List<Integer> list7 = Arrays.asList(1,2,3,4,5);
        Double collect7 = list7.stream().collect(Collectors.averagingInt(Integer::intValue));
        System.out.println(collect7);

        //maxBy 根据指定比较器找到流中最大的元素
        List<Integer> list8 = Arrays.asList(1,2,3,4,5);
        Optional<Integer> collect8 = list8.stream()
                .collect(Collectors.maxBy(Comparator.comparingInt(Integer::intValue)));
        System.out.println(collect8.get());

        //minBy 根据指定比较器找到流中最小的元素
        List<Integer> list9 = Arrays.asList(1,2,3,4,5);
        Optional<Integer> collect9 = list9.stream()
                .collect(Collectors.minBy(Comparator.comparingInt(Integer::intValue)));
        System.out.println(collect9.get());

        //joining 将流中的元素连接成一个字符串,可以使用指定的分隔符
        List<String> list10 = Arrays.asList("a","b","c");
        String collect10 = list10.stream().collect(Collectors.joining("/"));
        System.out.println(collect10);
        //groupingBy 根据分类函数对流中的元素进行分组
        List<Person> list11 = Arrays.asList(
                new Person("L", 1, 18),
                new Person("J", 2, 18),
                new Person("A", 1, 30)
        );
        Map<Integer, List<Person>> collect11 = list11.stream()
                .collect(Collectors.groupingBy(Person::getSex));
        System.out.println(collect11);

        //reducing 对流中的元素进行规定约定的操作
        List<Integer> list12 = Arrays.asList(1,2,3,4,5);
        Optional<Integer> collect12 = list12.stream().collect(Collectors.reducing(Integer::sum));
        System.out.println(collect12.get());
        BinaryOperator<Integer> binaryOperator12=(x,y)->x+y;
        Optional<Integer> collect13 = list12.stream().collect(Collectors.reducing(binaryOperator12));
        System.out.println(collect13.get());

        //mapping 对流中的元素应用映射函数,并对结果进行收集
        List<Integer> list14 = Arrays.asList(1,2,3,4,5);
        List<String> collect14 = list14.stream()
                .collect(Collectors.mapping(String::valueOf, Collectors.toList()));
        System.out.println(collect14);

        Function<Integer,Integer> function15 =(s)->s*s;
        List<Integer> collect15 = list14.stream()
                .collect(Collectors.mapping(function15, Collectors.toList()));
        System.out.println(collect15);

        //collectingAndThen 包裹另一个收集器,对其结果进行二次处理
        List<Integer> list16 = Arrays.asList(1,2,3,4,5);
        Function<Integer,String> function16 =(s)->{
            int l =s*s;
            return "计算它的平方:" + l;
        };
        String collect16 = list16.stream()
                .collect(Collectors.collectingAndThen(Collectors.summingInt(Integer::intValue), function16));
        System.out.println(collect16);

7.3 Parallel Streams(扩展)

Java中的Parallel Streams是Java 8引入的一个新特性,它允许你以并行的方式处理数据集合,从而充分利用多核处理器的优势来提高程序的执行效率。通过使用Parallel Streams,你可以将原本顺序执行的任务分解成多个子任务,并在多个线程上同时执行这些子任务,从而加速数据的处理速度。

//示例
        List<Long> list = new ArrayList<>();
        for (long i = 1; i <=1_000_000 ; i++) {
            list.add(i);
        }

        long start1 = System.currentTimeMillis();
        List<Long> collect1 = list.stream()
                .map(s -> s * s)
                .collect(Collectors.toList());
        long end1 = System.currentTimeMillis();
        System.out.println(new StringBuffer().append(end1-start1).append("ms"));

        long start2 = System.currentTimeMillis();
        List<Long> collect2 = list.parallelStream()
                .map(s -> s * s)
                .collect(Collectors.toList());
        long end2 = System.currentTimeMillis();
        System.out.println(new StringBuffer().append(end2-start2).append("ms"));
使用并行流(parallel stream)需要注意:
确保你的任务是可以并行化的,即任务之间没有依赖关系,可以独立执行。
对于大规模数据集,使用并行流可以提高性能。但对于小数据集,顺序流可能更加高效。
避免在并行流中使用阻塞操作,这可能会导致线程阻塞和性能下降。
在使用并行流时,要注意线程安全问题,确保你的代码是线程安全的。

Java 7 常用新特性(补充)

1、二进制字面量

在Java 7中,引入了对二进制字面量的支持。二进制字面量以0b或0B开头,后跟一系列的0和1。

/* 示例 */
        int i =0b11111111;
        int j =0B00000010;
        System.out.println("i: "+i+"\n"+"j: "+j); //i: 255 j: 2

2、数字字面量下划线支持

在Java 7中,引入了对数字字面量下划线的支持。这个特性允许在数字字面量中添加下划线(_)作为分隔符,以提高数字的可读性。这对于表示非常大的数字或者需要分组显示的数字特别有用。这个特性不会影响数字的值,下划线只是作为视觉上的分隔符。下划线可以出现在数字字面量的任何位置,除了数字的首位和末位,以及小数点的前面和后面。这个特性只适用于整数和浮点数的字面量,不适用于十六进制或八进制字面量。此外,虽然下划线可以提高代码的可读性,但过度使用可能会使代码变得难以阅读,因此建议适度使用。

/* 示例 */
        int i=1_000_000;
        double r =3.14_1_5_92_7;
        long l=7_7_7_7L;
        System.out.println(i); //1000000
        System.out.println(r); //3.1415927
        System.out.println(l); //7777

3、switch中使用String

在Java 7之前,switch语句仅支持字节型(byte)、短整型(short)、整型(int)、字符型(char)、枚举(enum)以及从Java 5开始引入的字符串类型(String)。然而,在Java 7中,对于switch语句中使用String类型的支持得到了扩展,允许你在switch语句中直接使用字符串。switch语句对字符串的比较是区分大小写的,switch语句中字符串的比较是通过字符串的equals方法进行的

/* 示例 */
        String a ="List";
        switch (a){
            case "list":
                System.out.println("list");
                break;
            case "List":
                System.out.println("List");
                break;
            case "set":
                System.out.println("set");
                break;
            default:
                System.out.println("default");
        }

4、对集合类的语言支持

Java 7 对集合类(Collections)的语言支持主要体现在对泛型实例创建的简化以及"diamond"操作符的引入,它减少了泛型代码中的冗余和错误。

4.1 泛型实例创建的简化

在Java 7之前,当创建一个泛型集合时,通常需要为集合和它的元素类型都指定泛型参数。Java 7中,对于类型推断的改进使得这种指定变得不必要,因为编译器可以根据上下文自动推断类型。

/* 示例 */
        //Java 7之前写法
        List<String> list1 = new ArrayList<String>();
        
        //Java 7及以后的版本
        List<String> list2 = new ArrayList<>();

4.2 "diamond"操作符

"diamond"操作符在其他泛型上下文中得到应用,如方法返回类型、方法参数、构造函数参数等。它使得泛型代码更加简洁,减少了重复的类型参数声明。

/* 示例 */
        //Java 7之前写法
        List<String> list1 = Arrays.asList(new String[]{"a", "b", "c"});

        //Java 7及以后的版本
        List<String> list2 = Arrays.asList("a", "b", "c");
/* asList 源码 */
	
	// <T>:表示数组中对象的类,编译器可通过上下文自动推断类型
    public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

5、自动资源管理

在Java 7中,为了更方便地管理资源(如文件流、数据库连接、网络连接等),引入了自动资源管理(Automatic Resource Management)的概念,这个特性允许开发者在try语句块中声明一个或多个资源,这些资源在try语句块执行完毕后会自动关闭。这避免了手动关闭资源的繁琐操作,并减少了因忘记关闭资源而导致的资源泄露问题。要使用这个特性,资源类必须实现AutoCloseable接口或Closeable接口(Closeable接口是AutoCloseable接口的子接口)。

/* 示例 */
	try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
	    String line;
	    while ((line = br.readLine()) != null) {
	        System.out.println(line);
	    }
	} catch (IOException e) {
	    e.printStackTrace();
	}

在上面的代码中,BufferedReader实现了Closeable接口,因此在try语句块执行完毕后,BufferedReader会自动关闭,无需手动调用br.close()。

6、try-catch多异常捕获

在Java 7及以后的版本中,try-catch语句块支持捕获多个异常类型,这是通过在一个catch块中指定多个异常类型来实现的,这些类型之间用竖线(|)分隔。这种语法允许你在一个catch块中处理多个不同类型的异常,而无需为每个异常类型编写单独的catch块。

/* 示例 */
        //当try块中的代码抛出异常时,Java虚拟机(JVM)会检查catch块中列出的异常类型,并找到第一个与抛出的异常类型匹配的catch块。
        try {
            int i =1/0; // class java.lang.ArithmeticException

            String s =null; //class java.lang.NullPointerException
            s.indexOf(0);
        }catch (ArithmeticException | NullPointerException e){
            System.out.println("程序报错:"+e.getClass());
        }

7、文件流

在Java 7中,文件流(File Streams)的处理得到了显著改进,特别是通过引入java.nio.file包中的新API。这些新API提供了更简洁、更直观的方式来处理文件I/O操作,同时提供了对文件属性、文件访问权限以及异步文件I/O的更全面支持。

7.1 文件路径(Path)

java.nio.file.Path接口是文件路径的抽象表示。它提供了许多方法来操作路径,如解析、组合、规范化等。Paths类是一个工具类,提供了静态方法来创建Path对象。

/* 示例 */
        Path path = Paths.get("C:\\Users\\777\\Desktop","MyPaths.txt");
        System.out.println(path); //C:\Users\777\Desktop\MyPaths.txt

7.2 文件属性(FileAttribute)

Java 7引入了FileAttribute接口,它允许你获取和设置文件的各种属性,如创建时间、最后访问时间、文件类型等。

/* 示例 */
        Path path = Paths.get("D:\\File","MyPaths.txt");
        System.out.println(path);

        BasicFileAttributes basicFileAttributes = Files.readAttributes(path, BasicFileAttributes.class);
        System.out.println(
                "文件创建时间:"+basicFileAttributes.creationTime()+"\n"+
                "文件大小"+basicFileAttributes.size()
        );

7.3 文件I/O

java.nio.file包中的Files类提供了一组静态方法,用于简化文件I/O操作。以下是一些常见方法:

检查文件路径是否存在
/* 示例 */
        Path path = Paths.get("D:\\File","MyPaths.txt");
        try{
            //检查文件路径是否存在
            boolean exists = Files.exists(path);
            System.out.println(exists);
        }catch (IOException e){
            System.out.println(e.getClass());
            e.printStackTrace();
        }
创建目录
/* 示例 */
        Path path = Paths.get("D:\\File","MyPaths");
        try{
            /*
            创建目录,如果目录已存在,会抛出java.nio.file.FileAlreadyExistsException
            如果是上级路径目录不存在,会抛出java.nio.file.NoSuchFileException
            */
            //创建目录
            Files.createDirectory(path);
        }catch (IOException e){
            System.out.println(e.getClass());
            e.printStackTrace();
        }
读取文件
/* 示例 */
        Path path = Paths.get("D:\\File","MyPaths.txt");
        try{
            //读取文件
            List<String> lines = Files.readAllLines(path);
            System.out.println(lines);
        }catch (IOException e){
            System.out.println(e.getClass());
            e.printStackTrace();
        }
写入文件
/* 示例 */
        Path path = Paths.get("D:\\File","MyPaths.txt");
        try{
            //写入文件
            String content = "Hello, World!";
            Files.write(path, content.getBytes());
        }catch (IOException e){
            System.out.println(e.getClass());
            e.printStackTrace();
        }
复制文件
/* 示例 */
        Path path = Paths.get("D:\\File","MyPaths.txt");
        Path copyPath = Paths.get("D:\\File","Copy_Paths.txt");
        try{
            /*
            复制文件,如果目标文件已存在,会抛出java.nio.file.FileAlreadyExistsException
            * */
            //复制文件
            Files.copy(path,copyPath);
        }catch (IOException e){
            System.out.println(e.getClass());
            e.printStackTrace();
        }

/****************************/

		/*
		强制复制文件
		*/
        Path path = Paths.get("D:\\File","MyPaths.txt");
        Path copyPath = Paths.get("D:\\File","Copy_Paths.txt");
        try{
            //使用copy方法第三个参数强制复制文件
            Files.copy(path,copyPath,StandardCopyOption.REPLACE_EXISTING);
        }catch (IOException e){
            System.out.println(e.getClass());
            e.printStackTrace();
        }

移动文件
/* 示例 */
        Path path = Paths.get("D:\\File","MyPaths.txt");
        Path movePath = Paths.get("D:\\File","Move_Paths.txt");
        try{
            /*
            移动文件,如果目标文件已存在,会抛出java.nio.file.FileAlreadyExistsException
            * */
            //移动文件
            Files.move(path,movePath);
        }catch (IOException e){
            System.out.println(e.getClass());
            e.printStackTrace();
        }

/****************/

		/*
		强制移动文件
		*/
        Path path = Paths.get("D:\\File","MyPaths.txt");
        Path movePath = Paths.get("D:\\File","Move_Paths.txt");
        try{
            //使用move方法第三个参数强制移动文件
            Files.move(path,movePath,StandardCopyOption.REPLACE_EXISTING);
        }catch (IOException e){
            System.out.println(e.getClass());
            e.printStackTrace();
        }

删除文件
/* 示例 */
        Path path = Paths.get("D:\\File","MyPaths.txt");
        try{
            //删除目录文件
            Files.delete(path);
        }catch (IOException e){
            System.out.println(e.getClass());
            e.printStackTrace();
        }

7.4 异步文件I/O

Java 7引入了异步文件I/O,允许非阻塞的文件读写操作。AsynchronousFileChannel类提供了异步读写文件的方法。

/* 读文件示例 */
        Path path = Paths.get("D:\\File","My_Paths.txt");
        try(
                AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
        ){

            ByteBuffer buffer = ByteBuffer.allocate(1024);
            channel.read(buffer,0,buffer,new CompletionHandler<Integer,ByteBuffer>(){
                @Override
                public void completed(Integer result, ByteBuffer attachment) {
                    // 完成读取后
                    attachment.flip(); //切换为读数据模式
                    while (attachment.hasRemaining()) {
                        System.out.print((char) attachment.get());
                    }
                }

                @Override
                public void failed(Throwable exc, ByteBuffer attachment) {
                    // 读取失败后
                    exc.printStackTrace();
                }
            });
        }catch (Exception e){
            e.printStackTrace();
        }
/* 写文件示例 */
        Path path = Paths.get("D:\\File","My_Paths.txt");
        try(
                AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
        ){
            ByteBuffer buffer = ByteBuffer.allocate(64);
            buffer.put("写入文字".getBytes());
            buffer.flip();//切换为读数据模式
            channel.write(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {
                @Override
                public void completed(Integer result, ByteBuffer attachment) {
                    System.out.println("写入完成");
                }

                @Override
                public void failed(Throwable exc, ByteBuffer attachment) {
                    exc.printStackTrace();
                }
            });
        }catch (Exception e){
            e.printStackTrace();
        }

7.5 文件遍历

在Java 7中,java.nio.file包提供了Files和Path类,它们提供了一种强大的方式来遍历文件系统。特别是,Files类中的walk和walkFileTree方法提供了遍历文件系统的能力。

Files.walk方法

Files.walk方法默认会遍历所有的子目录。如果你只想遍历顶层目录,你可以传递一个参数1给Files.walk方法。

/* 示例 */
        Path path = Paths.get("D:","File");
        try (
                Stream<Path> walk = Files.walk(path);
                ){
            walk.forEach(System.out::println);
        }catch (Exception e){
            System.out.println(e.getClass());
            e.printStackTrace();
        }
Files.walkFileTree方法

Files.walkFileTree允许你提供一个FileVisitor,你可以在其中定义如何处理每个文件。
示例:
当我们使用Files.delete删除目录时,如果目录不为空(目录内还有文件),则会抛出java.nio.file.DirectoryNotEmptyException异常。

        Path path = Paths.get("D:","File");//路径目录非空
        try {
            Files.delete(path);
        }catch (Exception e){
            System.out.println(e.getClass());
            e.printStackTrace();
        }

此时需要使用Files.walkFileTree方法遍历目录,先删除路径目录下的文件,最后再删除目录本身。

/* 示例 */
        Path path = Paths.get("D:","File");//路径目录非空
        try {
            Files.walkFileTree(path, new FileVisitor<Path>() {
                //访问目录前调用
                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                    System.out.println("开始遍历目录:"+dir);
                    return FileVisitResult.CONTINUE;
                }

                //遍历目录时调用
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    System.out.println("执行文件操作(delete):"+file);
                    Files.delete(file);
                    return FileVisitResult.CONTINUE;
                }

                访问失败时调用
                @Override
                public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                    System.out.println("Failed File!!! "+file);
                    return FileVisitResult.CONTINUE;
                }

                //遍历目录完成后调用
                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                    System.out.println("执行目录操作(delete):"+dir);
                    Files.delete(dir);
                    return FileVisitResult.CONTINUE;
                }
            });
        }catch (Exception e){
            System.out.println(e.getClass());
            e.printStackTrace();
        }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1567633.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【随笔】Git 基础篇 -- 分支与合并 git rebase(十)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

【Pt】马灯贴图绘制过程 05-铁丝与渲染出图

目录 效果 步骤 一、基本材质 二、浮尘 三、渲染 效果 步骤 一、基本材质 CtrlAlt鼠标右键选中指定的纹理集 在智能材质中将“Iron Forged Old”加入图层 将智能材质“Iron Forged Old”文件夹打开&#xff0c;将图层“Base”和“Edge”的基本颜色改暗一点 二、浮尘 新…

PHP+python高校教务处工作管理系统q535p

开发语言&#xff1a;php 后端框架&#xff1a;Thinkphp/Laravel 前端框架&#xff1a;vue.js 服务器&#xff1a;apache 数据库&#xff1a;mysql 运行环境:phpstudy/wamp/xammp等 系统根据现有的管理模块进行开发和扩展&#xff0c;采用面向对象的开发的思想和结构化的开发方…

21.兼容性测试

考试频率低&#xff1b; 一般考兼容性测试会结合web测试&#xff1b;&#xff08;兼容性矩阵&#xff09; 主要议题&#xff1a; 1.兼容性测试概述 2.硬件兼容性测试 最低配置不讲究工作负载&#xff0c;意思是软件能够运行的最低要求环境&#xff1b; 推荐配置&#xff0c…

【精品方案】智慧金融大数据分析平台总体架构方案

以下是部分PPT内容&#xff0c;请您参阅。如需下载完整PPTX文件&#xff0c;请前往星球获取&#xff1a; 1.实现数据共享 通过数据平台实现数据集中&#xff0c;确保金融集团各级部门均可在保证数据隐私和安全的前提下使用数据&#xff0c;充分发挥数据作为企业重要资产的业务价…

Nacos 服务发现 快速入门

Nacos 服务发现 快速入门 一、Nacos 服务发现 – 什么是服务发现 &#xff1f; 1、 Nacos 服务发现-什么是服务发现 在微服务架构中&#xff0c;整个系统会按职责能力划分为多个服务&#xff0c;通过服务之间协作来实现业务目标。 这样在我们的代码中免不了要进行服务间的远程…

[HackMyVM]靶场Zurrak

难度:medium kali:192.168.56.104 靶机:192.168.56.140 端口扫描 # nmap -sV -A 192.168.56.140 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-03-30 16:59 CST Nmap scan report for 192.168.56.140 Host is up (0.00039s latency). Not shown: 996 closed tcp po…

三相异步发电机在两相坐标系下的数学模型和状态方程

目录 1、异步发电机在两相静止坐标系下的数学模型 &#xff08;1&#xff09;磁链方程&#xff1a; &#xff08;2&#xff09;电压方程 &#xff08;3&#xff09;转矩方程 &#xff08;4&#xff09;异步电动机在两相静止坐标系&#xff08; &#xff09;上的数学模型 2、…

AcWing---转圈游戏---快速幂

太久没写快速幂了... 这是一道数学题orz&#xff0c;能看出来的话答案就是 &#xff0c;但是很大&#xff0c;同时还要mod n&#xff0c;直接用快速幂即可。 快速幂模版&#xff1a; long long int power(long long int a,long long int b,long long int mod){long long int r…

YUNBEE云贝-技术分享:PostgreSQL分区表

引言 PostgreSQL作为一款高度可扩展的企业级关系型数据库管理系统&#xff0c;其内置的分区表功能在处理大规模数据场景中扮演着重要角色。本文将深入探讨PostgreSQL分区表的实现逻辑、详细实验过程&#xff0c;并辅以分区表相关的视图查询、分区表维护及优化案例&#xff0c;…

基于深度学习的番茄成熟度检测系统(网页版+YOLOv8/v7/v6/v5代码+训练数据集)

摘要&#xff1a;在本博客中&#xff0c;我们深入探讨了基于YOLOv8/v7/v6/v5的番茄成熟度检测系统。核心技术基于YOLOv8&#xff0c;同时融合了YOLOv7、YOLOv6、YOLOv5的算法&#xff0c;对比了它们在性能指标上的差异。本文详细介绍了国内外在此领域的研究现状、数据集的处理方…

OpenHarmony实战:轻量级系统之移植验证

OpenHarmony芯片移植完成后&#xff0c;需要开展OpenHarmony兼容性测试以及芯片SDK功能性测试。除可获得测试认证之外&#xff0c;还可以在开发阶段提前发现缺陷&#xff0c;大幅提高代码质量。 OpenHarmony兼容性测试 OpenHarmony兼容性测试是XTS&#xff08;OpenHarmony生态…

基于深度学习的植物叶片病毒识别系统(网页版+YOLOv8/v7/v6/v5代码+训练数据集)

摘要&#xff1a;本文深入研究了基于YOLOv8/v7/v6/v5的植物叶片病毒识别系统&#xff0c;核心采用YOLOv8并整合了YOLOv7、YOLOv6、YOLOv5算法&#xff0c;进行性能指标对比&#xff1b;详述了国内外研究现状、数据集处理、算法原理、模型构建与训练代码&#xff0c;及基于Strea…

手搓链表(java)(不完整)

手搓链表&#xff08;java&#xff09;&#xff08;不完整&#xff09; 文章目录 手搓链表&#xff08;java&#xff09;&#xff08;不完整&#xff09;前言一、代码1.MyLinkedList类&#xff1a;2.测试类&#xff1a; 总结 前言 提示&#xff1a;以下是本篇文章正文内容&…

精品PPT-2023年无人驾驶汽车车联网网络安全方案

以下是部分PPT内容&#xff0c;请您参阅。如需下载完整PPTX文件&#xff0c;请前往星球获取&#xff1a; 无人驾驶安全架构是一个复杂的系统&#xff0c;它涉及到多个关键组件和层次&#xff0c;以确保无人驾驶车辆在各种情况下都能安全、可靠地运行。以下是一些主要的无人驾驶…

苹果手表Apple Watch录了两个半小时的录音,却只能播放4秒,同步到手机也一样,还能修复好吗?

好多人遇到这个情况&#xff0c;用苹果手表Apple Watch录音&#xff0c;有的录1个多小时&#xff0c;有的录了3、4小时&#xff0c;甚至更长时间&#xff0c;因为手表没电&#xff0c;忘记保存等原因造成录音损坏&#xff0c;都是只能播放4秒&#xff0c;同步到手机也一样&…

AI绘图:Stable Diffusion ComfyUI局部重绘与智能扩图全面教程

前言 在数字艺术创作中&#xff0c;局部重绘和智能扩图是两个非常重要的功能。局部重绘允许我们在保留原有图像的基础上&#xff0c;对特定区域进行修改或创新。而智能扩图则能够帮助我们在图像的边缘添加新的元素&#xff0c;从而扩展图像的内容。本文将详细介绍如何在Stable…

鼎捷T100二次开发资料大全 T100 webservice开发明细 4GL从入门到实战 T100实战例子 鼎捷二次开发DEMO 鼎捷单档双档开发

在ERP实施公司做顾问四五年&#xff0c;参与企业实施ERP十多个项目&#xff0c;熟悉企业ERP流程&#xff0c;在实施过程遇到众多问题&#xff0c;提出了不少根据企业具体情况的解决方案。   曾经参与鼎捷Tiptop GP、T100实施十多个项目&#xff0c;具有丰富的二次开发经验&am…

代码随想录算法训练营DAY16|C++二叉树Part.3|104.二叉树的最大深度、111.二叉树的最小深度、222.完全二叉树的节点个数

文章目录 104.二叉树的最大深度思路伪代码CPP代码 111.二叉树的最小深度思路伪代码CPP代码 222.完全二叉树的节点个数思路视为普通二叉树-递归视为普通二叉树-迭代利用完全二叉树特性-递归 伪代码视为普通二叉树-递归伪代码视为普通二叉树-迭代伪代码利用完全二叉树特性-递归伪…

SCP 从Linux快速下载文件到Windows本地

需求&#xff1a;通过mobaxterm将大文件拖动到windows本地速度太慢。 环境&#xff1a;本地是Windows&#xff0c;安装了Git。 操作&#xff1a;进入文件夹内&#xff0c;鼠标右键&#xff0c;点击Git Bash here&#xff0c;然后输入命令即可。这样的话&#xff0c;其实自己本…