当前位置:   article > 正文

Java 8更新:新特性与优化一览_java8 361优化了什么

java8 361优化了什么

目录 

 一、方法和构造函数引用

二、允许在接口中有默认方法实现

三、时间日期API

四、内置函数式接口

1.Predicate

2.Function

3.Optional

4.Streams

5.Filter

6.Sorted

7.Map

8.Match

9.Count

10.Reduce

11.Parallel Streams

五、Lambda 表达式

六、Stream API


 

 一、方法和构造函数引用

  1. Converter<String, Integer> converter = Integer::valueOf;
  2. Integer converted = converter.convert("123");
  3. System.out.println(converted); // 123

Java 8 允许你通过::关键字获取方法或者构造函数的的引用。 上面的例子就演示了如何引用一个静态方法。 而且, 我们还可以对一个对象的方法进行引用:

  1. class Something {
  2.   String startsWith(String s) {
  3.   return String.valueOf(s.charAt(0));
  4.  }
  5. }
  6. Something something = new Something();
  7. Converter<String, String> converter = something::startsWith;
  8. String converted = converter.convert("Java");
  9. System.out.println(converted); // "J"

让我们看看如何使用::关键字引用构造函数。 首先我们定义一个示例bean, 包含不同的构造方法:

  1. class Person {
  2. String firstName;
  3.  String lastName;
  4.  Person() {}
  5.  Person(String firstName, String lastName) {
  6.   this.firstName = firstName;
  7.  this.lastName = lastName;
  8. }
  9. }

接下来, 我们定义一个person工厂接口, 用来创建新的person对象:

  1. interface PersonFactory<P extends Person> {
  2.  P create(String firstName, String lastName);
  3. }

然后我们通过构造函数引用来把所有东西拼到一起, 而不是像以前一样, 通过手动实现一个工厂来这么做。

  1. PersonFactory<Person> personFactory = Person::new;
  2. Person person = personFactory.create("Peter", "Parker");

我们通过Person::new来创建一个Person类构造函数的引用。 Java编译器会自动地选择合适的构造函数来匹配PersonFactory.create函数的签名, 并选择正确的构造函数形式

二、允许在接口中有默认方法实现

  1. interface Formula {
  2. default double sqrt(int a) {
  3. return Math.sqrt(a);
  4. }
  5. }
  6. Formula formula = new Formula() {
  7. @Override
  8. public double calculate(int a) {
  9. return sqrt(a * 100);
  10. }
  11. };

三、时间日期API

Timezones,LocalTime

四、内置函数式接口

1.Predicate

Predicate接口接受一个输入参数,返回一个布尔值结果。这个接口包含多种默认方法用于复杂的逻辑表达式(and、or和xor)。

  1. Predicate<String> predicate = (s) -> s.length() > 0;
  2. predicate.test("foo"); // true
  3. predicate.negate().test("foo"); // false
  4. Predicate<Boolean> nonNull = Objects::nonNull;
  5. Predicate<Boolean> isNull = Objects::isNull;
  6. Predicate<String> isEmpty = String::isEmpty;
  7. Predicate<String> isNotEmpty = isEmpty.negate();

2.Function

Function接口接收一个参数, 并返回单一的结果。 默认方法可以将多个函数串在一起( compse, andThen)

  1. Function<String, Integer> toInteger = Integer::valueOf;
  2. Function<String, String> backToString =
  3. toInteger.andThen(String::valueOf);
  4. backToString.apply("123"); // "123"

五、Lambda 表达式

Lambda 表达式可以用来创建匿名函数,它通常用于替代传统的匿名内部类。以下是一个简单的 Lambda 表达式示例,用于对列表中的元素进行操作:

  1. // 传统的匿名内部类方式
  2. List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
  3. Collections.sort(names, new Comparator<String>() {
  4. @Override
  5. public int compare(String o1, String o2) {
  6. return o1.compareTo(o2);
  7. }
  8. });
  9. // 使用 Lambda 表达式
  10. Collections.sort(names, (String o1, String o2) -> o1.compareTo(o2));

六、Stream API

Stream API 提供了一种新的处理集合数据的方式,它允许你以声明式的方式对集合进行操作。以下是一个使用 Stream API 对列表进行过滤、映射和归约的示例:

  1. import java.util.Arrays;
  2. import java.util.List;
  3. import java.util.stream.Collectors;
  4. public class StreamExample {
  5. public static void main(String[] args) {
  6. // 创建一个包含数字的列表
  7. List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
  8. // 使用 Stream API 过滤出偶数
  9. List<Integer> evenNumbers = numbers.stream()
  10. .filter(n -> n % 2 == 0)
  11. .collect(Collectors.toList());
  12. // 使用 Stream API 将数字映射为它们的平方
  13. List<Integer> squares = numbers.stream()
  14. .map(n -> n * n)
  15. .collect(Collectors.toList());
  16. // 使用 Stream API 对数字进行归约,计算所有数字的和
  17. int sum = numbers.stream()
  18. .reduce(0, (a, b) -> a + b);
  19. System.out.println("Even numbers: " + evenNumbers);
  20. System.out.println("Squares: " + squares);
  21. System.out.println("Sum: " + sum);
  22. }
  23. }

 1.Streams

java.util.Stream表示了某一种元素的序列, 在这些元素上可以进行各种操作。 Stream操作可以是中间操作, 也可以是完结操作。 完结操作会返回一个某种类型的值, 而中间操作会返回流对象本身, 并且你可以通过多次调用同一个流操作方法来将操作结果串起来( 就像StringBuffer的append方法一样) 。 Stream是在一个源的基础上创建出来的, 例如java.util.Collection中的list或者set( map不能作为Stream的源) 。 Stream操作往往可以通过顺序或者并行两种方式来执行。我们先了解一下序列流。 首先, 我们通过string类型的list的形式创

建示例数据:

  1. List<String> stringCollection = new ArrayList<>();
  2. stringCollection.add("ddd2");
  3. stringCollection.add("aaa2");
  4. stringCollection.add("bbb1");
  5. stringCollection.add("aaa1");
  6. stringCollection.add("bbb3");
  7. stringCollection.add("ccc");
  8. stringCollection.add("bbb2");
  9. stringCollection.add("ddd1");

Java 8中的Collections类的功能已经有所增强, 你可以之直接通过调用Collections.stream()或者
Collection.parallelStream()方法来创建一个流对象。

2.Filter

Filter接受一个predicate接口类型的变量, 并将所有流对象中的元素进行过滤。 该操作是一个中间操作, 因此它允许我们在返回结果的基础上再进行其他的流操作( forEach) 。 ForEach接受一个function接口类型的变量, 用来执行对每一个元素的操作。 ForEach是一个中止r操作 它不返回流, 所以我们不能再调用其他的流操作。

  1. stringCollection
  2. .stream()
  3. .filter((s) -> s.startsWith("a"))
  4. .forEach(System.out::println);
  5. // "aaa2", "aaa1"

 3.Optional

Optional不是一个函数式接口, 而是一个精巧的工具接口, 用来防止NullPointerException产生。  所以我们在这里快速地浏览一下Optional的工作原理。Optional是一个简单的值容器, 这个值可以是null, 也可以是nonnull。 考虑到一个方法可能会返回一个non-null的值, 也可能返回一个空值。 为了不直接返回null, 我们在Java 8中就返回一个Optional.

  1. Optional<String> optional = Optional.of("bam");
  2. optional.isPresent(); // true
  3. optional.get(); // "bam"
  4. optional.orElse("fallback"); // "bam"
  5. optional.ifPresent((s) -> System.out.println(s.charAt(0))); //"b"

4.Sorted

Sorted是一个中间操作, 能够返回一个排过序的流对象的视图。 流对象中的元素会默认按照自然顺序进行排序, 除非你自己指定一个Comparator接口来改变排序规则。

  1. stringCollection
  2. .stream()
  3. .sorted()
  4. .filter((s) -> s.startsWith("a"))
  5. .forEach(System.out::println);
  6. // "aaa1", "aaa2"

一定要记住, sorted只是创建一个流对象排序的视图, 而不会改变原来集合中元素的顺序。 原来string集合中的元素顺序是没有改变的。

  1. System.out.println(stringCollection);
  2. // ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1

5.Map

map是一个对于流对象的中间操作, 通过给定的方法, 它能够把流对象中的每一个元素对应到另外一个对象上。 下面的例子就演示了如何把每个string都转换成大写的string. 不但如此, 你还可以把每一种对象映射成为其他类型。 对于带泛型结果的流对象, 具体的类型还要由传递给map的泛型方法来决定。

  1. stringCollection
  2. .stream()
  3. .map(String::toUpperCase)
  4. .sorted((a, b) -> b.compareTo(a))
  5. .forEach(System.out::println);
  6. // "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"

6.Match

匹配操作有多种不同的类型, 都是用来判断某一种规则是否与流对象相互吻合的。 所有的匹配操作都是终结操作, 只返回一个boolean类型的结果。

  1. boolean anyStartsWithA =
  2. stringCollection
  3. .stream()
  4. .anyMatch((s) -> s.startsWith("a"));
  5. System.out.println(anyStartsWithA); // true
  6. boolean allStartsWithA =
  7. stringCollection
  8. .stream()
  9. .allMatch((s) -> s.startsWith("a"));
  10. System.out.println(allStartsWithA); // false
  11. boolean noneStartsWithZ = stringCollection
  12. .stream()
  13. .noneMatch((s) -> s.startsWith("z"));
  14. System.out.println(noneStartsWithZ); // true

7.Count

Count是一个终结操作, 它的作用是返回一个数值, 用来标识当前流对象中包含的元素数量。

  1. long startsWithB =
  2. stringCollection
  3. .stream()
  4. .filter((s) -> s.startsWith("b"))
  5. .count();
  6. System.out.println(startsWithB); // 3

8.Reduce

该操作是一个终结操作, 它能够通过某一个方法, 对元素进行削减操作。 该操作的结果会放在一个Optional变量里返回。

  1. Optional<String> reduced =
  2. stringCollection
  3. .stream()
  4. .sorted()
  5. .reduce((s1, s2) -> s1 + "#" + s2);
  6. reduced.ifPresent(System.out::println);
  7. // "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"

9.Parallel Streams

Parallel Streams像上面所说的, 流操作可以是顺序的, 也可以是并行的。 顺序操作通过单线程执行, 而并行操作则通过多线程执行。下面的例子就演示了如何使用并行流进行操作来提高运行效率, 代码非常简单。首先我们创建一个大的list, 里面的元素都是唯一的:

  1. int max = 1000000;
  2. List<String> values = new ArrayList<>(max);
  3. for (int i = 0; i < max; i++) {
  4. UUID uuid = UUID.randomUUID();
  5. values.add(uuid.toString());
  6. }

流可以并行执行, 在大量输入元素上可以提升运行时的性能。 并行流使用公共的 ForkJoinPool , 由 ForkJoinPool.commonPool() 方法提供。 底层线程池的大小最大为五个线程 — 取决于CPU的物理核数。

  1. Arrays.asList("a1", "a2", "b1", "c2", "c1")
  2. .parallelStream()
  3. .filter(s -> {
  4. System.out.format("filter: %s [%s]\n",
  5. s, Thread.currentThread().getName());
  6. return true;
  7. })
  8. .map(s -> {
  9. System.out.format("map: %s [%s]\n",s, Thread.currentThread().getName());
  10. return s.toUpperCase();
  11. })
  12. .sorted((s1, s2) -> {
  13. System.out.format("sort: %s <> %s [%s]\n",s1, s2, Thread.currentThread().getName());
  14. return s1.compareTo(s2);
  15. })
  16. .forEach(s -> System.out.format("forEach: %s[%s]\n",s,Thread.currentThread().getName()));

输出结果如下:

filter: c2 [ForkJoinPool.commonPool-worker-3]
filter: c1 [ForkJoinPool.commonPool-worker-2]
map: c1 [ForkJoinPool.commonPool-worker-2]
filter: a2 [ForkJoinPool.commonPool-worker-1]
map: a2 [ForkJoinPool.commonPool-worker-1]
filter: b1 [main]
map: b1 [main]
filter: a1 [ForkJoinPool.commonPool-worker-2]
map: a1 [ForkJoinPool.commonPool-worker-2]
map: c2 [ForkJoinPool.commonPool-worker-3]
sort: A2 <> A1 [main]
sort: B1 <> A2 [main]
sort: C2 <> B1 [main]
sort: C1 <> C2 [main]
sort: C1 <> B1 [main]
sort: C1 <> C2 [main]
forEach: A1 [ForkJoinPool.commonPool-worker-1]
forEach: C2 [ForkJoinPool.commonPool-worker-3]
forEach: B1 [main]
forEach: A2 [ForkJoinPool.commonPool-worker-2]
forEach: C1 [ForkJoinPool.commonPool-worker-1]

就像你看到的那样, 并行流使用了所有公共的 ForkJoinPool 中的可用线程来执行流式操作。 在连续的运行中输出可能有所不同, 因为所使用的特定线程是非特定的。
 

sort 只在主线程上串行执行。 实际上, 并行流上的 sort 在背后使用了Java8中新的方法 Arrays.parallelSort() 。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/560943
推荐阅读
相关标签
  

闽ICP备14008679号