当前位置: 首页 > news >正文

个人网站域名快速备案页面布局

个人网站域名快速备案,页面布局,类似freenom的免费域名网站,公众号开发流程Java8 新特性 Java 8 的革新之路 自 1995 年首次发布以来#xff0c;Java 已经成为世界上最广泛使用的编程语言之一。随着时间的推移#xff0c;Java 经历了多次版本更新#xff0c;其中最具里程碑意义的便是 Java 8 的发布。这个版本引入了许多重大变革#xff0c;包括 …Java8 新特性 Java 8 的革新之路 自 1995 年首次发布以来Java 已经成为世界上最广泛使用的编程语言之一。随着时间的推移Java 经历了多次版本更新其中最具里程碑意义的便是 Java 8 的发布。这个版本引入了许多重大变革包括 Lambda 表达式、Stream API 和函数式编程等新特性。这些变化不仅提升了 Java 开发者的生产力还使得 Java 在性能、简洁性和可读性方面达到了新的高度。 本文将深入探讨 Java 8 的主要新特性并通过示例代码和实际应用案例帮助你理解这些特性的优势和使用场景。无论你是 Java 初学者还是经验丰富的开发者这篇文章都将为你提供一个全面了解 Java 8 新特性的平台帮助你在日常开发中更高效地利用这些功能。 让我们一起踏上 Java 8 的革新之旅探索如何通过这些新特性提高我们的代码质量和开发效率。 主要内容 Lambda 表达式核心函数式接口方法引用与构造器引用Stream API新时间日期 API接口中默认方法与静态方法其他新特性 新特性简介 速度更快代码更少简洁增加了新的语法 Lambda 表达式强大的 Stream API便于并行可以最大化减少空指针异常 Optional – 因为这个类的方法 为什么便于运行 三点原因 Stream API 可以让我们轻松地对集合进行并行处理。Lambda表达式 可以让我们以一种简洁的方式定义匿名函数这种方式可以使代码更加简洁。方式引用已经存在的方法或构造函数可以避免我们重复编写相似的代码。 综上所述Java8 新特性便于并行的原因是它们可以让我们以一种简洁的方式处理集合数据同时充分利用多核 CPU 的优势从而提高程序的执行效率。 1、Lambda 表达式 何为 Lambda 表达式 Lambda 是一个匿名函数作为一种更紧凑的代码风格使 Java 的语言表达能力得到了提升可以写出更简洁、更灵活的代码。 代码示例 Runnable 接口从匿名内部类到 Lambda 的转换**(无参)** // 匿名内部类 Runnable r1 new Runnable() {Overridepublic void run() {System.out.println(Hello World!);} };// Lambda 表达式 Runnable r1 () - System.out.println(Hello Lambda!);Comparator 接口参数传递 – 从匿名内部类到 Lambda 的转换**(有参)** // 使用匿名内部类作为参数传递 TreeSetString ts new TreeSet(new ComparatorString() {Overridepublic int compare(String o1, String o2) {return Interger.compare(o1.length(), o2.length());} });// 使用 Lambda 表达式作为参数传递 TreeSetString ts2 new TreeSet((o1, o2) - Integer.compare(o1.length(), o2.length()) // 升序排序 );Listener 接口 JButton button new JButton(); button.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent e) {e.getItem(); } });// Lambda button.addItemListener(e - e.getItem()); 语法 - 箭头操作符简介 Lambda 表达式在 Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “-”该操作符被称为 Lambda 操作符或箭头操作符。 它将 Lambda 分为两个部分 左侧指定了 Lambda 表达式需要的所有参数右侧指定了 Lambda 体即 Lambda 表达式要执行的功能 六种格式 格式一 无参无返回值Lambda 体只需要一条语句即可 Runnable r1 () - System.out.println(Hello Lambda!);格式二 Lambda 需要一个参数 ConsumerString fun (args) - System.out.println(args);格式三 Lambda 只需要一个参数时参数的小括号可以省略 ConsumerString fun args - System.out.println(args);格式四 Lambda 需要两个参数并且有返回值时 BinaryOperatorLong bo (x, y) - {System.out.println(实现函数接口方法);return x y; };格式五 当 Lambda 体只有一条语句时return 与大括号可以省略 BinaryOperatorLong bo (x, y) - x y;格式六 带参数的数据类型 – 数据类型可以省略如上所示因为可由编译器推断得出称为“类型推断” BinaryOperatorLong bo (Long x, Long y) - {System.out.println(实现函数接口方法);return x y; };类型推断 所谓的“类型推断”是指Lambda 表达式中的参数类型依赖于上下文环境都是由编译器推断得出的。 在 Lambda 表达式中无需指定类型程序依然可以编译这是因为 javac 根据程序的上下文在后台推断出了参数的类型。 总结 大致可分为三种类型 格式一为一种 – 无需参数无返回值Lambda 体一条语句即可格式二、三为一种 – 需要一个参数无返回值可省略参数小括号也是一条语句即可格式四、五、六为一种 – 需要两种参数有返回值可以省略大括号与 return 参数类型均可省略推荐使用一、二、五 2、函数式接口 何为函数式接口 函数式接口是指只包含一个抽象方法的接口该接口的对象可以通过 Lambda 表达式来创建。 若 Lambda 表达式抛出一个受检异常那么该异常需要在目标接口的抽象方法上进行声明 一般建议函数式接口上使用 FunctionalInterface 注解修饰 这样做可以检查它是否是一个函数式接口同时 javadoc 也会包含一条声明说明这个接口是一个函数式接口 FunctionalInterface 注解用于标识该接口是函数式接口防止在接口中添加多余的抽象方法。 不是所有的函数式接口都有 FunctionalInterface 注解修饰但是建议所有函数式接口都应该加上该注解因为这有助于编译器检查该接口是否符合函数式接口的要求即只有一个抽象方法。如果该注解标注在有多个抽象方法的接口上则编译器会报错提示该接口不符合函数式接口的定义。同时加上该注解也可以让其他开发者更容易地理解该接口的用途和特点。 什么是抽象方法 抽象方法指的是没有实现代码的方法只有方法声明包括方法名、返回值类型、参数列表和异常列表。在 Java 中如果一个类中包含了抽象方法那么这个类必须被声明为抽象类因为抽象方法无法被直接调用。只有当一个类继承了抽象类并实现了抽象方法才能创建该类的对象并调用该方法。 抽象方法的语法格式为在方法声明中使用 abstract 关键字修饰方法方法体中不包含实现代码。例如 public abstract void draw();抽象方法的作用是为了让子类实现自己的方法逻辑从而实现多态性和代码复用。在设计模式中也经常使用抽象方法来定义基础框架和算法流程具体实现由子类来完成。 在函数式接口中由于该接口只包含一个抽象方法因此该方法默认为抽象方法不需要显式使用 abstract 关键字进行修饰。 代码示例 FunctionalInterface public interface MyInterface {void myMethod(); } MyInterface myInterface () - System.out.println(Hello World!); myInterface.myMethod(); // 输出Hello World!自定义函数式接口 只要方法的参数是函数式接口都可以用 Lambda 表达式 FunctionalInterface public interface MyNumber {double getValue(); }// 在函数式接口中使用泛型 public interface MyFuncT {T getValue(T t); }// 作为参数传递 Lambda 表达式 public String toUpperString(MyFuncString) mf, String str) {return mf.getValue(str); }String newStr toUpperString((str) - str.toUpperCase(), abcdef); // 该 Lambda 表达式的作用是将字符串转换成大写字母并返回 System.out.println(newStr); // ABCDEF作为参数传递 Lambda 表达式 为了将 Lambda 表达式作为参数传递接收 Lambda 表达式的参数类型必须是与该 Lambda 表达式兼容的函数式接口的类型。 例如一个计算器接口可以定义如下的函数式接口 FunctionalInterface public interface Calculator {int calculate(int x, int y); }在该接口中定义了一个抽象方法 calculate(int x, int y)接受两个整型参数 x 和 y 返回一个整型结果。该接口标记了 FunctionalInterface 注解表示该接口是一个函数式接口。 然后可以使用 Lambda 表达式来创建该接口的实例例如 Calculator add (x, y) - x y; Calculator subtract (x, y) - x - y; Calculator multiply (x, y) - x * y; Calculator divide (x, y) - x / y;在这个例子中分别使用 Lambda 表达式创建了加法、减法、乘法、除法四种计算器操作的实例这些实例都是 Calculator 函数式接口的实例。 然后可以使用这些实例进行计算例如 int result add.calculate(2, 3); // 加法运算结果为 5在这个例子中使用加法操作的实例 add 对参数 2 和 3 进行了加法运算并将结果赋值给 result 变量。 总之自定义函数式接口可以根据具体的业务需求定义然后使用 Lambda 表达式来创建该接口的实例从而实现对业务逻辑的封装和复用。 Java 内置四大核心函数式接口 四种消费型接口、供给型接口、函数型接口、断定型接口 1. Consumer 接口 – 消费型接口 Consumer 接口定义了一个接受一个泛型参数并返回 void 的操作。该接口有一个抽象方法 accept(T t)接收一个泛型参数 T表示该操作的输入参数无返回值。 源码解析 package java.util.function;import java.util.Objects;FunctionalInterface public interface ConsumerT {/*** 对给定的参数执行操作** param t 要执行操作的参数*/void accept(T t);/*** 返回一个组合了多个Consumer的新Consumer表示执行顺序为该Consumer接口先执行然后执行after中的Consumer接口** param after 要执行的另一个Consumer接口* return 组合后的新Consumer接口*/default ConsumerT andThen(Consumer? super T after) {Objects.requireNonNull(after);return (T t) - {accept(t);after.accept(t);};} }在这个源码中首先使用 FunctionalInterface 注解标记了该接口是一个函数式接口。然后定义了一个抽象方法accept(T t)表示对给定的参数执行操作并无返回值。接着定义了一个默认方法 andThen(Consumer? super T after)用于组合多个 Consumer 实例表示执行顺序为该 Consumer 接口先执行然后执行 after 中的Consumer 接口。 总之Consumer接口可以用于对给定的参数执行操作例如打印、修改状态等。该接口提供了一个默认方法 andThen 可以用于组合多个 Consumer 实例从而实现更加复杂的操作。 应用场景 Consumer 接口可以用于对集合进行遍历、对异步任务结果进行处理、以及对对象状态进行修改等场景中。使用Consumer 接口可以使代码更加简洁、易于维护增强代码的可读性和可重用性。 以下是一些常见的场景 集合遍历可以使用 Consumer 接口对集合中的每个元素进行操作。 例如对一个字符串列表中的每个字符串进行大写转换并输出 ListString list Arrays.asList(apple, banana, orange); ConsumerString toUpperCase s - System.out.println(s.toUpperCase()); list.forEach(toUpperCase);在这个例子中定义了一个字符串列表 list其中包含三个字符串元素。然后定义了一个 Consumer 实例 toUpperCase用于将字符串转换为大写并输出。接着使用 forEach 方法遍历 list 中的每个元素并将 toUpperCase 实例作为参数传入实现对每个字符串的大写转换和输出操作。 异步任务处理可以使用 Consumer 接口对异步任务的结果进行处理。 例如对一个异步任务的结果进行打印 CompletableFutureString future CompletableFuture.supplyAsync(() - Hello, World!); ConsumerString printResult s - System.out.println(s); future.thenAccept(printResult); // Hello, World!在这个例子中使用 CompletableFuture 创建一个异步任务该任务返回一个字符串 Hello, World!。然后定义了一个 Consumer 实例 printResult用于打印异步任务的结果。使用 thenAccept 方法注册了一个 Consumer 类型的回调函数该回调函数的作用是在 future 对象执行完毕后将结果传递给 printResult Lambda 表达式并输出。表示当异步任务完成时对结果进行处理,体现了异步任务执行完成后的回调机制。 状态修改可以使用 Consumer 接口对对象的状态进行修改。 例如修改一个订单对象的状态 public class Order {private String status;// getter和setter方法// ... } ConsumerOrder updateStatus o - o.setStatus(已发货); Order order new Order(); updateStatus.accept(order);在这个例子中定义了一个 Order 类其中包含一个状态属性 status。然后定义了一个 Consumer 实例 updateStatus用于将订单状态修改为 已发货。接着创建了一个订单对象 order并将 updateStatus 实例作为参数传入实现对订单状态的修改。 2. Supplier 接口 – 供给型接口 Supplier 接口产生给定泛型类型的结果。与 Function 接口不同Supplier 接口不接受参数。 该接口有一个抽象方法 get()用于返回一个泛型参数 T表示该操作的结果。 源码解析 package java.util.function;FunctionalInterface public interface SupplierT {/*** 获取一个结果** return 表示操作结果的泛型参数T*/T get(); }在这个源码中首先使用 FunctionalInterface 注解标记了该接口是一个函数式接口。然后定义了一个抽象方法 get()用于获取一个结果并返回一个泛型参数 T。该方法没有参数仅返回一个表示操作结果的泛型参数。 总之Supplier 接口主要用于提供一个泛型参数类型的结果例如获取当前时间、生成随机数、从数据库中获取数据等。Supplier 接口的 get() 方法没有参数返回一个表示操作结果的泛型参数可以与其它函数式接口进行组合使用实现更加复杂的操作。 应用场景 用于提供一个泛型参数类型的结果例如生成随机数、从数据库中获取数据、获取当前时间等场景中。 生成随机数 SupplierInteger randomSupplier () - new Random().nextInt(100); int randomNum randomSupplier.get();从数据库中获取数据 public class SupplierExample {public static void main(String[] args) {SupplierListString supplier () - {ListString list new ArrayList();try {ResultSet resultSet DriverManager.getConnection(jdbc:mysql://localhost:3306/test, root, password).createStatement().executeQuery(select * from user);while (resultSet.next()) {list.add(resultSet.getString(name));}} catch (SQLException e) {e.printStackTrace();}return list;};ListString result supplier.get();System.out.println(result.stream().collect(Collectors.joining(, )));} }获取当前时间 SupplierLocalDateTime timeSupplier LocalDateTime::now; LocalDateTime currentTime timeSupplier.get();3. Function 接口 – 函数型接口 Function 接口接收一个参数并生成结果。默认方法可用于将多个函数链接在一起compose, andThen package java.util.function;import java.util.Objects;FunctionalInterface public interface FunctionT, R {//将Function对象应用到输入的参数上然后返回计算结果。R apply(T t);//将两个Function整合并返回一个能够执行两个Function对象功能的Function对象。default V FunctionV, R compose(Function? super V, ? extends T before) {Objects.requireNonNull(before);return (V v) - apply(before.apply(v));}//返回一个由原始Function执行完后再执行after Function的新Functiondefault V FunctionT, V andThen(Function? super R, ? extends V after) {Objects.requireNonNull(after);return (T t) - after.apply(apply(t));}//接收任意类型参数并返回相同类型参数的Function//作用快速创建一个无需处理参数的Function实例static T FunctionT, T identity() {return t - t;} }应用场景 Function 接口主要用于将一个类型的值转化为另一个类型的值。它接受一个参数并返回一个结果通常用于在数据处理、转换或映射过程中使用。 数据转换和映射 FunctionString, Integer toInteger Integer::valueOf; FunctionString, String backToString toInteger.andThen(String::valueOf); backToString.apply(123); // 123数据过滤和筛选 ListString list Arrays.asList(apple, banana, orange, grape); FunctionString, Boolean filterFunction s - s.startsWith(a); ListString filteredList list.stream().filter(filterFunction::apply).collect(Collectors.toList()); System.out.println(filteredList); // [apple]数据处理和转换 ListString list Arrays.asList(apple, banana, orange, grape); FunctionString, Integer mapFunction String::length; ListInteger lengthList list.stream().map(mapFunction::apply).collect(Collectors.toList()); System.out.println(lengthList); // [5, 6, 6, 5]4. Predicate 接口 – 断定型接口 Predicate 接口是只有一个参数的返回布尔类型值的 断言型 接口。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑比如与或非 源码解析 package java.util.function; import java.util.Objects;FunctionalInterface public interface PredicateT {// 该方法是接收一个传入类型,返回一个布尔值.此方法应用于判断.boolean test(T t);//and方法与关系型运算符相似两边都成立才返回truedefault PredicateT and(Predicate? super T other) {Objects.requireNonNull(other);return (t) - test(t) other.test(t);}// 与关系运算符!相似对判断进行取反default PredicateT negate() {return (t) - !test(t);}//or方法与关系型运算符||相似两边只要有一个成立就返回truedefault PredicateT or(Predicate? super T other) {Objects.requireNonNull(other);return (t) - test(t) || other.test(t);}// 该方法接收一个Object对象,返回一个Predicate类型.用于判断两个对象是否相等static T PredicateT isEqual(Object targetRef) {return (null targetRef)? Objects::isNull: object - targetRef.equals(object);} 应用场景 Predicate 接口可以用于对集合进行过滤、对方法参数进行校验、以及实现复杂的逻辑判断等场景中。使用Predicate 接口可以使代码更加简洁、易于维护增强代码的可读性和可重用性。 以下是一些常见的场景 集合过滤可以使用 Predicate 接口对集合进行过滤例如筛选出所有大于等于 10 的整数 ListInteger list Arrays.asList(1, 5, 10, 15, 20); PredicateInteger predicate i - i 10; ListInteger filteredList list.stream().filter(predicate).collect(Collectors.toList());在这个例子中首先创建了一个整型列表 list然后定义了一个 Predicate 实例 predicate用于判断一个整数是否大于等于 10。接着使用 stream 对列表进行流操作在流操作中使用 filter 方法传入 predicate 实例对整数进行过滤最后将过滤结果收集到一个新的列表中。 参数校验可以使用 Predicate 接口对方法参数进行校验例如校验一个字符串是否为空 public void doSomething(String str) {PredicateString isEmpty s - s null || s.length() 0;if (isEmpty.test(str)) {throw new IllegalArgumentException(字符串不能为空);}// ... }在这个例子中定义了一个 Predicate 实例 isEmpty用于判断一个字符串是否为空。在方法中对传入参数str进行校验如果为空则抛出异常。 复杂逻辑判断可以使用 Predicate 接口对多个条件进行组合实现更加复杂的逻辑判断。例如判断一个字符串是否包含数字和大写字母 String str Hello, World! 123; PredicateString containsDigit s - s.matches(.*\\d.*); PredicateString containsUpperCase s - s.matches(.*[A-Z].*); if (containsDigit.and(containsUpperCase).test(str)) {System.out.println(字符串符合要求); }在这个例子中定义了两个 Predicate 实例 containsDigit 和 containsUpperCase分别用于判断一个字符串是否包含数字和大写字母。在判断中使用 and 方法将两个实例组合起来表示字符串必须同时包含数字和大写字母才符合要求。最后使用 test 方法对字符串进行判断如果符合要求则输出相应信息。 小结 Consumer 接口 抽象方法 void accept(T t); 接收一个泛型参数 T表示该操作的输入参数无返回值 一个默认方法 andThen(Consumer? super T after)用于组合多个 Consumer 实例表示执行顺序为- 该 Consumer 接口先执行然后执行 after 中的Consumer 接口。 Supplier 接口 抽象方法 T get; 用于返回一个泛型参数 T表示该操作的结果。 Function 接口 抽象方法 R apply(T t); 接收参数 T 然后返回计算结果 两个默认方法compose, andThen用于将多个函数链接在一起 一个静态方法 identity() 用于快速创建一个无需处理参数的 Function 实例。 Predicate 接口 抽象方法 boolean test(T t); 返回一个布尔值应用于判断。 包含多种默认方法来将 Predicate 组合成其他复杂的逻辑比如与and或or取反negate 一个静态方法 isEqual用于判断两个对象是否相等 其他接口 3、方法引用与构造器引用 概念 使用操作符 “::” 将方法名和对象或类的名字分隔开来。 使用场景 当要传递给 Lambda 体的操作已经有实现的方法了可以使用方法引用实现抽象方法的参数列表必须与方法引用方法的参数列表保持一致 一方法引用 1. 类 :: 静态方法 类 :: 静态方法ClassName::staticMethodName FunctionString, Integer strToInt Integer::parseInt; int result strToInt.apply(123);2. 对象 :: 实例方法 对象 :: 实例方法instance::instanceMethodName ListString list Arrays.asList(apple, banana, orange, grape); list.forEach(System.out::println);3. 类 :: 实例方法 类 :: 实例方法ClassName::instanceMethodName ListString list Arrays.asList(apple, banana, orange, grape); list.stream().map(StringUtils::toUppercase).forEach(System.out::println);二构造器引用 格式ClassName::new 与函数式接口相结合自动与函数式接口中方法兼容。可以把构造器引用赋值给定义的方法与构造器参数列表要与接口中抽象方法的参数列表一致。 FunctionString, Person createPerson Person::new; Person person createPerson.apply(Tom); 三数组引用 格式type[] :: new // 创建一个长度为 10 的数组 FunctionInteger, String[] createArray String[]::new; String[] array createArray.apply(10); // 将其中所有元素设置为 0 Arrays.stream(arr).forEach(int[]::setAll);4、强大的 Stream API 概念 Stream 是 Java8 中处理集合的关键抽象概念它可以指定你希望对集合进行的操作可以执行非常复杂的查找、过滤和映射数据等操作。 使用 Stream API 对集合数据进行操作就类似于使用 SQL 执行的数 据库查询。也可以使用 Stream API 来并行执行操作。简而言之 Stream API 提供了一种高效且易于使用的处理数据的方式。 流Stream到底是什么 是数据渠道用于操作数据源集合、数组等所生成的元素序列。 “集合讲的是数据流讲的是计算” 注意 Stream 自己不会存储元素。Stream 不会改变源对象。相反他们会返回一个持有结果的新 Stream。Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。 操作三步骤 一创建 Stream 顺序流与并行流 Java8 中的 Collection 接口被扩展提供了两个获取流的方法 default Stream stream() : 返回一个顺序流 default Stream parallelStream() : 返回一个并行流 并行流就是把一个内容分成多个数据块并用不同的线程分别处理每个数据块的流。 Java8 中将并行进行了优化我们可以很容易的对数据进行并行操作。Stream API 可以声明性地通过 parallel() 与 sequential() 在并行流与顺序流之间进行切换。 数组流 Java8 中的 Arrays 的静态方法 stream() 可以获取数组流 static Stream stream(T[] array): 返回一个流 重载形式能够处理对应基本类型的数组 public static IntStream stream(int[] array)public static LongStream stream(long[] array)public static DoubleStream stream(double[] array) 由值创建流 可以使用静态方法 Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数。 public static Stream of(T… values) : 返回一个流 无限流 由函数创建流。可以使用静态方法 Stream.iterate() 和 Stream.generate(), 创建无限流。 迭代 public static Stream iterate(final T seed, final UnaryOperator f) 生成 public static Stream generate(Supplier s) 二Stream 的中间操作 什么是中间操作 中间操作是对 Stream 对象进行加工处理的操作用于对 Stream 中的元素进行处理、筛选、过滤、排序、去重等操作。中间操作可以使用链式调用的方式进行连续操作**每次操作都会返回一个新的 Stream 对象**这样可以构建出一条操作流水线。 惰性求值 多个中间操作可以连接起来形成一个流水线除非流水线上触发终止操作否则中间操作不会执行任何的处理而在终止操作时一次性全部处理称为“惰性求值” 。 API 筛选与切片 方法描述filter(Predicate)接收 Lambda 从流中排除某些元素distinct()筛选通过流所生成元素的 hashCode() 和 equals() 去除重复元素limit(long maxSize)截断流使其元素不超过给定数量。skip(long n)跳过元素返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个则返回一个空流。与 limit(n) 互补 映射 方法描述map(Function f)接收一个函数作为参数该函数会被应用到每个元素上并将其映射成一个新的元素。mapToDouble(ToDoubleFunction f)接收一个函数作为参数该函数会被应用到每个元素上产生一个新的 DoubleStream。mapToInt(ToIntFunction f)接收一个函数作为参数该函数会被应用到每个元素上产生一个新的 IntStream。mapToLong(ToLongFunction f)接收一个函数作为参数该函数会被应用到每个元素上产生一个新的 LongStream。flatMap(Function f) 接收一个函数作为参数将流中的每个值都换成另 一个流然后把所有流连接成一个流。 排序 方法描述sorted()产生一个新流其中按自然顺序排序sorted(Comparator comp)产生一个新流其中按比较器顺序排序 三终止操作 何为终止操作 终止操作是对 Stream 对象执行最终操作的操作用于触发 Stream 的处理流程并返回最终的结果。终止操作可以是有返回值的例如collect()方法也可以是没有返回值的例如forEach()方法。终端操作会从流的流水线生成结果。其结果可以是任何不是流的值例如List、Integer甚至是 void。 API 查找与匹配 方法描述allMatch(Predicate p)检查是否匹配所有元素anyMatch(Predicate p)检查是否至少匹配一个元素noneMatch(Predicate p检查是否没有匹配所有元素findFirst()返回第一个元素count()返回流中元素总数max(Comparator c)返回流中最大值min(Comparator c)返回流中最小值forEach(Consumer)内部迭代(使用 Collection 接口需要用户去做迭代称为外部迭代。相反Stream API 使用内部迭代一一它帮你把迭代做了) 归约 方法描述reduce(T iden,BinaryOperator可以将流中元素反复结合起来得到一个值返口 Treduce(BinaryOperator b)可以将流中元素反复结合起来得到一个值。返 OptionalT **备注**map 和 reduce 的连接通常称为 map-reduce 模式因 Google 用它来进行网络搜索而出名 收集 方法描述collect(Collector c)将流转换为其他形式。接收一个 Collector 接口的实现用于给 Stream 中元素做汇总的方法 Collector 接口中方法的实现决定了如何对流执行收集操作(如收 集到 List、Set、Map)。 但是 Collectors 实用类提供了很多静态 方法可以方便地创建常见收集器实例具体方法与实例如下表 ForK/Join 框架 什么是 Fork/Join 框架 **Fork/Join 框架**就是在必要的情况下将一个大任务进行拆分 (fork) 成若干个小任务拆到不可再拆时再将一个个的小任务运算的结果进行 join 汇总。 并行流 parallelStream 可多线程执行是基于 ForkJoin 框架实现的 forEach() 用到的就是多线程 Fork/Join 框架与传统线程池的区别 采用“工作窃取”模式work-stealing当执行新的任务时它可以将其拆分分成更小的任务执行并将小任务加到线程队列中然后再从一个随机线程的队列中窃取一个并把它放在自己的队列中继续执行。 相对于一般的线程池实现fork/join 框架的优势体现在对其中包含的任务的处理方式上。 在一般的线程池中,如果一个线程正在执行的任务由于某些原因无法继续运行,那么该线程会处于等待状态。 而在 fork/join 框架实现中,如果某个子问题由于等待另外一个子问题的完成而无法继续运行。那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行这种方式是动态的减少了线程的等待时间并提高了性能。 Fork/Join 框架提供了一些特殊的方法比如 fork() 和 join() 等用于处理分治任务简化了代码的编写和管理。 5、新时间日期 API LocalDate、LocalTime、LocalDateTime 三种类的实例都是不可变的对象。 LocalDate – 表示使用 ISO-8601 日历系统的日期LocalTime – 表示使用 ISO-8601 日历系统的时间LocalDateTime – 表示使用 ISO-8601 日历系统的日期和时间 LocalDateTime.class //日期时间 format: yyyy-MM-ddTHH:mm:ss.SSS LocalDate.class //日期 format: yyyy-MM-dd LocalTime.class //时间 format: HH:mm:ss注ISO-8601 日历系统是国际标准化组织制定的现代公民的日期和时间的表示。 各种方法如下 instant 时间戳 用于“时间戳”的运算。它是以 Unix 元年(传统的设定为 UTC 时区 1970 年 1 月 1 日午夜时分)开始所经历的描述进行运算。 Duration 和 Period Duration: 用于计算两个**“时间”间隔** import java.time.Duration; import java.time.LocalDateTime; public class DurationExample {public static void main(String[] args) {//获取当前时间LocalDateTime start LocalDateTime.now();System.out.println(开始时间 start);//模拟程序执行try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}//获取执行结束时间LocalDateTime end LocalDateTime.now();System.out.println(结束时间 end);//计算时间差Duration duration Duration.between(start, end);System.out.println(程序执行时间 duration.toMillis() 毫秒);} }Period: 用于计算两个**“日期”间隔** import java.time.LocalDate; import java.time.Period; public class PeriodExample {public static void main(String[] args) {//获取当前日期LocalDate start LocalDate.now();System.out.println(开始日期 start);//模拟时间间隔LocalDate end start.plusDays(30);System.out.println(结束日期 end);//计算日期差Period period Period.between(start, end);System.out.println(日期间隔 period.getDays() 天);} }操作日期的类 TemporalAdjuster: 时间校正器。 例如有时我们可能需要获取将日期调整到“下个周日”等操作。 TemporalAdjusters: 该类通过静态方法提供了大量的常用 TemporalAdjuster 的实现方便开发者对日期进行各种调整操作。 import java.time.DayOfWeek; import java.time.LocalDate; import java.time.temporal.TemporalAdjusters; public class TemporalAdjusterExample {public static void main(String[] args) {//获取当前日期LocalDate date LocalDate.now();System.out.println(当前日期 date);//获取本月的第一天LocalDate firstDayOfMonth date.with(TemporalAdjusters.firstDayOfMonth());System.out.println(本月第一天 firstDayOfMonth);//获取本月的最后一天LocalDate lastDayOfMonth date.with(TemporalAdjusters.lastDayOfMonth());System.out.println(本月最后一天 lastDayOfMonth);//获取下一个周二LocalDate nextTuesday date.with(TemporalAdjusters.next(DayOfWeek.TUESDAY));System.out.println(下一个周二 nextTuesday);} }日期时间格式化和解析的类 java.time.format.DateTimeFormatter 类 该类提供了三种格式化方法 1. 预定义的标准格式 DateTimeFormatter 类提供了一些预定义的标准格式例如 ISO_DATE、ISO_TIME、ISO_DATE_TIME 等等这些标准格式已经定义好了日期时间的格式开发者可以直接使用。 2. 语言环境相关的格式 DateTimeFormatter 类还提供了一些与语言环境相关的格式例如 ofLocalizedDate(FormatStyle style)、ofLocalizedTime(FormatStyle style)、ofLocalizedDateTime(FormatStyle style) 等等这些格式会根据不同的语言环境自动适配不同的日期时间格式。 3. 自定义的格式 例如 ofPattern(String pattern) 方法可以传入一个字符串参数用于定义自己想要的日期时间格式yyyy-MM-dd HH:mm:ss 就是一个自定义的日期时间格式。 时区的处理 Java8 中加入了对时区的支持带时区的时间为分别为ZonedDate、ZonedTime、ZonedDateTime 其中每个时区都对应着 ID地区 ID 都为 “{区域}/{城市}”的格式 例如 Asia/Shanghai 等 ZoneId该类中包含了所有的时区信息getAvailableZoneIds(): 可以获取所有时区时区信息of(id): 根据指定的时区信息获取 ZoneId 对象 讲一下与传统日期的转换 Java8 中的日期和时间 API 与传统的日期类如 java.util.Date 和 java.util.Calendar之间存在一些差异因此在进行日期转换时需要注意以下几点 java.util.Date 和 java.util.Calendar 类是可变的而 Java8 中的日期和时间类是不可变的因此在进行转换时需要特别注意。 java.util.Date 类的精度是毫秒级别而 Java8 中的日期和时间类的精度可以达到纳秒级别因此在进行转换时需要注意精度的损失。 Java8 中的日期和时间类之间可以相互转换例如可以将 LocalDateTime 对象转换为 Instant 对象但是需要注意转换后的时区和精度问题。 以下是一个简单的 Java8 和传统日期类java.util.Date和java.util.Calendar之间的转换示例 import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Calendar; import java.util.Date; public class DateConversionExample {public static void main(String[] args) {// Java 8日期类转换为传统日期类LocalDateTime dateTime LocalDateTime.now();Date date Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());Calendar calendar Calendar.getInstance();calendar.setTime(date);System.out.println(Java 8日期类转换为传统日期类 calendar.getTime());// 传统日期类转换为Java 8日期类calendar Calendar.getInstance();calendar.set(2022, Calendar.APRIL, 28);date calendar.getTime();dateTime LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());System.out.println(传统日期类转换为Java 8日期类 dateTime);// Java 8日期类之间的转换dateTime LocalDateTime.now();Instant instant dateTime.atZone(ZoneId.systemDefault()).toInstant();dateTime LocalDateTime.ofInstant(instant, ZoneId.systemDefault());System.out.println(Java 8日期类之间的转换 dateTime);} }6、接口中的默认方法与静态方法 概念 Java8 中允许接口中包含具有具体实现的方法该方法称为 “默认方法”默认方法使用 default 关键字修饰并允许添加静态方法。 接口默认方法的“类优先”原则 如果一个类实现了多个接口而这些接口中定义了同名的默认方法那么编译器就会产生歧义因为它不知道应该使用哪个默认方法。为了解决这个问题Java 8 引入了“类优先”Class Priority的原则即如果一个类继承了另一个类并且实现了一个接口而这两者中都定义了同名的默认方法那么类中的方法优先于接口中的方法。 注意在使用“类优先”原则时如果类中的方法不是完全覆盖了接口中的方法那么编译器会报错此时需要在类中显式地调用接口中的方法。 interface MyInterface {default void myMethod() {System.out.println(Default method in interface);} } class MyClass {public void myMethod() {System.out.println(Method in class);} } class MyImplementation extends MyClass implements MyInterface { } public class DefaultMethodExample {public static void main(String[] args) {MyImplementation obj new MyImplementation();obj.myMethod(); // 输出 Method in class} }7、其他新特性 Optional 类 Optional 类 (java.util.Optional) 是一个容器类代表一个值存在或不存在原来用 null 表示一个值不存在现在 Optional 可以更好的表达这个概念。并且 可以避免空指针异常。 常用方法 Optional.of(T t): 创建一个 Optional 实例Optional.empty(): 创建一个空的 Optional 实例Optional.ofNullable(T t): 若 t 不为 null创建 Optional 实例,否则创建空实例isPresent(): 判断是否包含值orElse(T t): 如果调用对象包含值返回该值否则返回 torElseGet(Supplier s): 如果调用对象包含值返回该值否则返回 s 获取的值map(Function f): 如果有值对其处理并返回处理后的 Optional否则返回 Optional.empty()flatMap(Function mapper): 与 map 类似要求返回值必须是 Optional 重复注解与类型注解 Java8 对注解处理提供了两点改进可重复的注解及可用于类型的注解。 可重复的注解 在Java 8之前同一个注解不能在同一个地方重复使用这在某些情况下会导致代码的冗余。Java8 引入了可重复的注解它允许同一个注解在同一个地方重复使用。这种注解需要使用 Repeatable 元注解来标注。 举个例子假设我们有一个 Author 注解用于表示文章的作者。在 Java8 之前我们无法在同一个类或方法上使用多次 Author 注解而必须定义多个注解如 Author1、Author2 等。在 Java8 中我们可以使用可重复的注解来解决这个问题示例代码如下 Repeatable(Authors.class) interface Author {String name(); } interface Authors {Author[] value(); } Authors({Author(name Alice),Author(name Bob) }) public class Article {// ... }可用于类型的注解 Java8 还引入了一种新的注解类型 —— 类型注解Type Annotation它可以用于注解类型如类、接口、枚举、注解等上。这种注解需要使用新的元注解 Target 来标注同时需要指定 ElementType.TYPE_USE 作为注解的目标类型。 举个例子假设我们有一个 NotNull 注解用于表示一个类型不为 null。在 Java8 之前我们只能将它应用到方法的参数上而不能将其应用到类型上。在 Java8 中我们可以使用类型注解将其应用到类型上示例代码如下 interface NotNull {} class ExampleNotNull T {public void foo(ListNotNull String strings) {} }8、Java 8 实战 推荐参考此篇文章 https://javaguide.cn/java/new-features/java8-common-new-features.html 9、peek() peek() 方法是 Stream API 中的一个中间操作它允许你在不改变数据的情况下对流中的元素进行某种操作。peek() 方法接收一个 Consumer 接口的实现对流中的每个元素执行该操作并返回一个新的流其中包含与原始流相同的元素。 import java.util.stream.Stream;public class Main {public static void main(String[] args) {Stream.of(1, 2, 3, 4, 5).filter(n - n % 2 0).peek(System.out::println).collect(Collectors.toList());} }在这个示例中我们创建了一个包含 1 到 5 的整数流然后使用 filter() 方法过滤出偶数。接下来我们使用 peek() 方法打印每个元素最后使用 collect() 方法将流转换为列表。输出结果如下 2 4返回一个新的流有啥必要 返回一个新的流在某些情况下是有必要的因为这样可以保留原始流的状态。当你对一个流进行操作时例如过滤、映射或排序等原始流不会受到影响因为这些操作都是惰性的只有在需要时才会执行。 然而如果你在 forEach 方法中对元素进行了修改那么这些修改会影响到原始流。这是因为 forEach 方法返回的是一个 void它不能直接返回一个新的流。但是你仍然可以在 forEach 方法中对原始流进行操作然后使用 .collect() 方法将流转换为列表或其他集合类型。 总之返回一个新的流并不总是必要的但它在某些情况下是有用的特别是当你需要保留原始流的状态时。 应用场景 peek() 方法主要用于调试。它可以用于查看流中的元素但不会改变流的状态。例如你可以使用 peek() 方法来查看一个整数流中的偶数但不会将它们从流中删除。这个方法在多线程的场景下也很有用因为它可以用于读取队列头部元素。 总之peek() 方法主要用于调试和多线程场景下读取队列头部元素。 html](https://javaguide.cn/java/new-features/java8-common-new-features.html)
http://www.ihoyoo.com/news/127984.html

相关文章:

  • 网站建设4038gzsseoul是哪个城市
  • 烟台消防建设信息网站购物帮–做特惠的导购网站
  • 成都网站制作龙兵科技网站怎样绑定域名
  • 网站开发与设计实训心得两千字长宁制作网站
  • 做个人博客的网站wordpress文章缩进
  • 网站如何做国外推广网页设计服务方案
  • 提升网站知名度定制旅游网站建设成都
  • 做美食网站赚钱吗网络维护招聘信息
  • 个人备案网站类型系部网站建设需求分析运行需求
  • 漳浦县建设局网站外贸公司如何接单
  • 做淘宝要用到哪些网站桂平市住房和城乡建设局门户网站
  • 做网站要用编程吗网站cdn 自己做
  • 外包网站设计哪家好网站外链平台的建设方法平台类型(至少5个)?
  • php mysql 网站开发实例教程淄博网站建设优化上汽
  • 好网站建设公司选择哪家好商务网站建设方案
  • 浙江省国有建设用地使用权建议网站小企业网站建设一般收费
  • apache多个网站小白怎么制作微信小程序
  • 银川网站建设联系电话个人网页设计尺寸是多少
  • 网站开发 后端内蒙古企业网站建设
  • 陕西省城乡建设学校网站集团网站设计公司
  • dw做响应式网站怎么样建立个人网站
  • 网站 建站模式遵义建站平台哪家好
  • godday网站建设个体户门头图片
  • 展示型网站模板代码建行企业银行app下载
  • 安庆哪些做网站的公司好宁夏做网站公司
  • git网站开发网页设计叫什么行业
  • 怎样建设外贸网站济宁seo
  • 网站所有人查询国外h5分享网站
  • 有哪些装修网站青州做网站的网络公司
  • 怎样构建自己的网站江苏网站建设 博敏网站