Java 7、Java 8常用新特性

目录

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

稀疏矩阵的三元组表表示法及其转置

1. 什么是稀疏矩阵 稀疏矩阵是指矩阵中大多数元素为零的矩阵。 从直观上讲&#xff0c;当元素个数低于总元素的30%时&#xff0c;这样的矩阵被称为稀疏矩阵。 由于该种矩阵的特点&#xff0c;我们在存储这种矩阵时&#xff0c;如果直接采用二维数组&#xff0c;就会十分浪费…

Kubernetes(k8s)核心资源解析:Pod详解

Kubernetes核心资源解析&#xff1a;Pod详解 1、什么是Pod&#xff1f;2、Pod 的组成3、Pod 如何管理多个容器4、Pod 的网络5、Pod 的存储方式6、Pod 的工作方式6.1 自主式 Pod6.2 监控和管理 Pod6.3 Pod 的创建流程 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收…

基于单片机的测时仪系统设计

**单片机设计介绍&#xff0c;基于单片机的测时仪系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的测时仪系统设计是一个结合了单片机技术与测时技术的综合性项目。该设计的目标是创建一款精度高、稳定性强且…

前端学习<四>JavaScript基础——03-常量和变量

常量&#xff08;字面量&#xff09;&#xff1a;数字和字符串 常量也称之为“字面量”&#xff0c;是固定值&#xff0c;不可改变。看见什么&#xff0c;它就是什么。 常量有下面这几种&#xff1a; 数字常量&#xff08;数值常量&#xff09; 字符串常量 布尔常量 自定义…

重磅!openGauss6.0创新版本,带着新特性正式发布了!

&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&#x1f61c;&#x1f61c; 中国DBA联盟(ACD…

编程生活day6--回文子串、蛇形填充数组、笨小猴、单词排序

回文子串 题目描述 给定一个字符串&#xff0c;输出所有长度至少为2的回文子串。 回文子串即从左往右输出和从右往左输出结果是一样的字符串&#xff0c;比如&#xff1a;abba&#xff0c;cccdeedccc都是回文字符串。 输入 一个字符串&#xff0c;由字母或数字组成。长度5…

求m和n的最大公约数(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int remainder 1;int m 0;int n 0;int middle 0;//提示用户&#xff1b;printf("请输入整数m和n的值&#xff…

处理SAP报错:消息GLT2076 没有项目种类分配到科目 1481010102/1000

财务新建了个科目入账时报错&#xff1a;没有项目种类分配到科目。 查了下原因。原来是我们公司实施时启用了凭证分割功能。其中有个配置是这样的&#xff1a;给总账科目分类&#xff1a;IMG-财务会计&#xff08;新&#xff09;-总账会计核算-业务交易-凭证分解-为文档拆分给总…

分布式架构中一些常用算法的理解

对分布式算法 - 一致性Hash算法的理解 一致性哈希算法是一种分布式算法&#xff0c;用于解决数据分布和负载均衡问题。它通过将数据和节点映射到一个哈希环上&#xff0c;实现了数据在节点之间的均匀分布和最小化数据迁移。 一致性哈希算法的核心思想是将数据和节点都映射到哈…

1.数据结构和算法

文章目录 数据结构逻辑结构集合结构线性结构树形结构图形结构 物理结构顺序存储结构链式存储结构 算法基本特性目标 总结数据结构总结算法总结 数据结构 「数据结构」指的是&#xff1a;数据的组织结构&#xff0c;用来组织、存储数据。 逻辑结构 逻辑结构&#xff08;Logic…

Dubbo入门项目搭建【Dubbo3.2.9、Nacos2.3.0、SpringBoot 2.7.17、Dubbo-Admin 0.6.0】

B站学习视频 基于Dubbo3.2.9、Nacos2.3.0、SpringBoot 2.7.17、Dubbo-Admin 0.6.0、Jdk1.8 搭建的Dubbo学习Demo 一、前置安装 1-1、Nacos 安装 我本地是通过docker-compose来安装nacos的&#xff0c;如果需要其它方式安装可以去百度找下教程&#xff0c;版本是2.3.0的 docker…

C语言要点细细梳理(下)

10. 运算符补充 10.1 位运算 位运算符&#xff1a;<< >> & | ~ ^ << >> &#xff1a;按位左移右移&#xff0c;移出去的数直接丢掉&#xff0c;符号不动 &&#xff1a;按位与 |&#xff1a; 按位或 ~&#xff1a;按位非 ^&#xff1a;按…

iOS使用CoreML运用小型深度神经网络架构对图像进行解析

查找一个图片选择器 我用的是ImagePicker 项目有点老了&#xff0c;需要做一些改造&#xff0c;下面是新的仓库 platform :ios, 16.0use_frameworks!target learnings dosource https://github.com/CocoaPods/Specs.gitpod ImagePicker, :git > https://github.com/KevinS…

基于VUE实现的餐厅经营游戏项目源码

WebMOOC 餐厅游戏 项目介绍 实现了一个类游戏的餐厅经营模拟&#xff0c;涉及的前端知识有移动端 HTML 页面布局及样式实现。实现了厨师、顾客等角色的关键操作&#xff0c;完成从顾客等位、点菜、烹饪、用餐、支付的一系列状态变更的数据、信息、交互、展现的变化及处理。 …

巨控560:走向国际,我们的设备如何拥抱远程控制技术?

走向国际&#xff0c;我们的设备如何拥抱远程控制技术&#xff1f; 描述&#xff1a;随着国内设备走向国际市场&#xff0c;客户需求的多样性和不确定性大大增加。本文将深入探讨在这一背景下&#xff0c;是否有必要为我们的设备加装远程PLC控制模块&#xff0c;以及如何应对频…

分布式系统架构中的相关概念

1.1、衡量网站的性能指标 响应时间&#xff1a;指执行一个请求从开始到最后收到响应数据所花费的总体时间。并发数&#xff1a;指系统同时能处理的请求数量。 并发连接数&#xff1a;指的是客户端向服务器发起请求&#xff0c;并建立了TCP连接。每秒钟服务器连接的总TCP数量请…

基于SSM+Jsp+Mysql的图书仓储管理系统

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

ospf的路由计算

LSA是链路状态信息&#xff08;描述接口信息&#xff09;&#xff0c;路由器将接口信息发给其他路由器&#xff0c;LSA有6个分类&#xff0c;1&#xff0c;2类描述区域内信息&#xff0c;3类是区域间的&#xff0c;5类是外部路由&#xff0c;4类是对5类的补充&#xff0c;7类是…

企微知识库优缺点解析:如何让其效益最大化

企业搭建企微知识库&#xff0c;作为企业内部知识的集中存储和共享平台&#xff0c;为企业带来了很多便利。但是&#xff0c;任何事物都有其两面性&#xff0c;企微知识库也不例外。今天我们就来详细探讨搭建企微知识库的优点和缺点&#xff0c;如何在使用企微知识库时使其发挥…

【群晖】NASTOOL-自动化处理影音视频工具

【群晖】NASTOOL-自动化处理影音视频 本文主要从获取、部署、使用、配置等方面进行手把手教学如何使用nastool工具进行影音视频自动化处理。从此靠别繁琐的网上各个网址找资源-下载-复制-改名-刮削等操作。 准备 DSM 7.1 &#xff08;我使用的是群晖 7.1 系统&#xff0c;不管…