Java6升级至Java8常用新特性

news2024/12/23 14:08:00

目录

  • 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();
        }


指南

部分文献从百度文心一言大数据模型获取,百度文心一言,中国人自己的ChatGPT。

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

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

相关文章

【Qt】窗口

目录 一、概述二、菜单栏&#xff08;QMenuBar&#xff09;三、工具栏&#xff08;QToolBar&#xff09;四、状态栏&#xff08;QStatusBar&#xff09;五、浮动窗口六、对话框 一、概述 Qt窗口是通过QMainWindow类来实现的。 QMainWindow是一个为用户提供主窗口程序的类&…

程序数据模型由OS还是硬件架构决定?

文章目录 前言硬件架构的作用OS的作用编译器的角色OS的数据模型参考 前言 在文章 1>>32的结果是1还是0 中提到了数据模型 L P 64 LP64 LP64 &#xff0c;并提出这个数据模型主要是由 U n i x Unix Unix 以及类 U n i x Unix Unix 的操作系统使用居多&#xff0c;例如…

SpringBoot 缓存预热

简介&#xff1a; SpringBoot集合RedisUtil和 CommadnLinRunner实现缓存预热 一、新建一个缓存抽象类 在redis模块里面 新建 /*** 缓存抽象类*/ Component public abstract class AbstractCache {// 初始化缓存public void initCache() {}public <T> T getCache(Strin…

虚拟现实(VR)项目的开发工具

虚拟现实&#xff08;VR&#xff09;项目的开发涉及到多种工具&#xff0c;这些工具可以帮助开发者从建模、编程到最终内容的发布。以下是一些被广泛认可的VR开发工具&#xff0c;它们覆盖了从3D建模到交互设计等多个方面。北京木奇移动技术有限公司&#xff0c;专业的软件外包…

PySpark的学习

一. 什么是PySpark 使用过的bin/pyspark 程序 , 要注意 , 这个只是一个 应用程序 , 提供一个 Python 解释器执行环境来运行 Spark 任务 现在说的 PySpark, 指的是 Python 的运行类库 , 是可以在 Python 代码中 :import pyspark PySpark 是 Spark 官方提供的一个 Python …

MP设置动态表名

Mybatis设置动态表名 Mybatis设置动态表名1.动态表名插件2.传递表名3.注意事项 Mybatis设置动态表名 1.动态表名插件 MybatisPlus中提供了一个动态表名的插件&#xff1a;https://baomidou.com/pages/2a45ff/#dynamictablenameinnerinterceptor 插件的部分源码如下&#xff…

【SpringCloud】Eureka注册中心

目 录 一.Eureka的结构和作用二.搭建 eureka-server1. 创建 eureka-server 服务2. 引入 eureka 依赖3. 编写启动类4. 编写配置文件5. 启动服务 三.服务注册1. 引入依赖2. 配置文件3. 启动多个user-service实例 四.服务发现1. 引入依赖2. 配置文件3. 服务拉取和负载均衡 总结 假…

【MATLAB源码-第24期】基于matlab的水声通信中海洋噪声的建模仿真,对比不同风速的影响。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 水声通信&#xff1a; 水声通信是一种利用水中传播声波的方式进行信息传递的技术。它在水下环境中被广泛应用&#xff0c;特别是在海洋科学研究、海洋资源勘探、水下军事通信等领域。 1. **传输媒介**&#xff1a;水声通信利…

【IC前端虚拟项目】mvu顶层集成的原则与技巧

【IC前端虚拟项目】数据搬运指令处理模块前端实现虚拟项目说明-CSDN博客 截止目前,所有的子模块编码均宣告完成,接下来就是封装顶层的时刻了。我自己规划和集成顶层一般有一个习惯,就是在top层下面封装core层和其他模块,比如mvu的top层下例化了mvu_reg和mvu_core两个模块,…

鸿蒙OS开发实战:【网络管理HTTP数据请求】

一、场景介绍 应用通过HTTP发起一个数据请求&#xff0c;支持常见的GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT方法。 二、 接口说明 HTTP数据请求功能主要由http模块提供。 使用该功能需要申请ohos.permission.INTERNET权限。 涉及的接口如下表&#xff0c;…

最优算法100例之18-列升序行升序的数组中查找元素

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样一…

WebScraper网页数据爬取可视化工具使用(无需编码)

前言 Web Scraper 是一个浏览器扩展&#xff0c;可以实现无需编码即可爬取网页上的数据。只需按照规则进行配置&#xff0c;即可实现一键爬取导出数据。 安装 进入Google应用商店安装此插件&#xff0c;安装步骤如下&#xff1a; 进入Google应用商店需要外网VPN才能访问&…

贪吃蛇:从零开始搭建一个完整的小游戏

目录 导语&#xff1a; 一、游戏框架 二、蛇的实现 三、绘制游戏界面 四、食物 五、移动蛇 六.得分系统&#xff0c;是否吃到食物 七、检查碰撞 八、处理按键事件 九、得分系统 十、游戏状态管理 导语&#xff1a; 贪吃蛇这个经典的小游戏&#xff0c;我上学的时候就…

用一个程序解决SQLite常见的各项操作(实用篇)

文章说明&#xff1a; 本篇文章是在之前的一篇文章SQLite3进行数据库各项常用操作基础上写的&#xff0c;将SQLite涉及到的常用的几种操作&#xff0c;以函数的形式处理成相互调用的形式。 因为之前的文章对基础操作已经解释过了&#xff0c;所以这里直接放置可执行代码和结果…

常见6种开源协议比较

前言 常见的开源许可协议有6种是比较常见和广泛使用的&#xff0c;每种协议都有其特定的使用场景和约束条件。这6种分别是GPL, LGPL&#xff0c;MIT许可证&#xff0c; Apache许可证&#xff0c;BSD许可证和Mozilla Public License&#xff08;MPL&#xff09;. 6种开源许可协议…

深度学习评价指标(1):目标检测的评价指标

1. 简述 在计算机视觉/深度学习领域&#xff0c;每一个方向都有属于自己的评价指标。通常在评估一个模型时&#xff0c;只需要计算出相应的评价指标&#xff0c;便可以评估算法的性能。同时&#xff0c;所谓SOTA&#xff0c;皆是基于某一评价指标进行的评估。 接下来&#xff0…

GitHub - 使用SSH进行连接

文章目录 前言开发环境单个SSH密钥1.1. 生成SSH密钥1.2. 添加SSH密钥1.3. 测试SSH连接2.1. 简化密钥密码输入 多个SSH密钥1.1. 生成/添加/测试SSH密钥2.1. 简化密钥密码输入 无密码密钥补充内容最后 前言 有一个SSH密钥跟了我很多年&#xff0c;更换电脑也不曾更换它。它不需要…

腾讯云轻量2核2G3M云服务器优惠价格61元一年,限制200GB月流量

腾讯云轻量2核2G3M云服务器优惠价格61元一年&#xff0c;配置为轻量2核2G、3M带宽、200GB月流量、40GB SSD盘&#xff0c;腾讯云优惠活动 yunfuwuqiba.com/go/txy 活动链接打开如下图&#xff1a; 腾讯云轻量2核2G云服务器优惠价格 腾讯云&#xff1a;轻量应用服务器100%CPU性能…

QT初识(1)

QT初识 桌面开发什么是QT下载QT安装好之后的工具AssisantDesignerQT Creator 创建一个简单的项目 我们今天来认识一下QT。 桌面开发 在了解QT&#xff0c;我们得了解一下桌面开发&#xff1a; 桌面开发指的是编写和构建在个人计算机或其他桌面操作系统&#xff08;如Windows、…

论文笔记 - :MonoLSS: Learnable Sample Selection For Monocular 3D Detection

论文笔记✍MonoLSS: Learnable Sample Selection For Monocular 3D Detection &#x1f4dc; Abstract &#x1f528; 主流做法限制 &#xff1a; 以前的工作以启发式的方式使用特征来学习 3D 属性&#xff0c;没有考虑到不适当的特征可能会产生不利影响。 &#x1f528; 本…