目录

1、速度更快

2、Lambda表达式

2.1、匿名内部类的Lambda转换

2.2、java8内置的四大核心函数式接口

2.3、方法引用和构造器

2.3.1、方法引用

2.3.2、构造器引用

2.3.3、数组引用

3、Stream API

3.1、stream API常用例子

3.2、stream映射

3.2.1、map

3.2.2、flatMap

3.3、stream排序与查找

3.4、map-reduce

3.5、collection

3.6、steamAPI练习

4、并行流

4.1、fork/join框架

4.2、顺序流与并行流比较

5、接口中的默认方法

6、新时间日期api

7、重复注解与类型注解

7.1、重复注解

7.2、类型注解

8、总结

9、参考资料


1、速度更快

jdk1.8对底层做了优化,使得速度更快了。jdk1.8取消了永久区,取而代之的是增加了元空间(MetaSpace),元空间直接使用了物理内存(RAM),因此运行速度会更快。

jdk1.8之后对哈希表做了优化,在jdk1.8之前,哈希表的结构是数组+链表,jdk1.7使用的是头插法,jdk1.7用的单链表是纵向延伸的。jdk1.8之后,增加了红黑树,jdk1.8之后的哈希表的结构是数组+链表+红黑树。jdk1.8的哈希表用的是尾插法,当哈希表容量达到总容量的3/4的时候(负载因子0.75),会进行扩容,扩容后的大小为当前容量*2。当哈希表中某个表项上面串的那一个单链表长度大于8的时候,这个单链表会转为红黑树。有关jdk1.8后的哈希表更多了解可以参考以下三篇文章

https://blog.csdn.net/zyt_java/article/details/105706125

https://www.cnblogs.com/shawn-sun/p/13871006.html

https://blog.csdn.net/u010890358/article/details/80496144/

2、Lambda表达式

Lambda表达式可以简化代码,尤其是对于需要使用到匿名内部类的。Lambda是一个匿名函数,我们可以把 Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。

Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “->”, 该操作符被称为 Lambda 操作符或剪头操作符。

它将 Lambda 分为两个部分:
左侧:指定了 Lambda 表达式需要的所有参数
右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能

语法格式:

2.1、匿名内部类的Lambda转换

//匿名内部类
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("HHH");
}
};
r1.run(); //lambda表达式
Runnable r2 = () -> {
System.out.println("HHH");
};
r2.run();

2.2、java8内置的四大核心函数式接口

定义:只包含一个抽象方法的接口称为“函数式接口”,通常在接口方法上用@FunctionalInterface修饰。

java8中四大函数式接口

  • Consumer<T>:消费型接口  void accept(T t);
  • Supplier<T>:供给型接口  T get();
  • Function<T,R>:函数型接口  R apply(T t);
  • Predicate<T>:boolean test(T t);
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier; /**
* @author: wu linchun
* @time: 2021/8/15 15:26
* @description:
*/ public class TestLambda02 {
public static void main(String[] args) {
//消费型接口:Consumer<T> 有参数,无返回值类型的接口
testConsumer(10000, (m) -> {
System.out.println(m);
}); //函数型接口:Function<T,R> 输入一个类型得参数,输出一个类型得参数,当然两种类型可以一致
System.out.println(testFunction("abc", (f) -> {
return f.toUpperCase();
})); //供给型接口:Supplier<T> 只有产出,没人输入,就是只有返回值,没有入参
System.out.println(testSupplier(10, () -> {
return (int) (Math.random() * 100);
})); //断言型接口:Predicate<T> 输入一个参数,输出一个boolean类型得返回值
List<String> list = Arrays.asList("asadax", "a", "cv", "bcv", "asaqs", "fksix", "ls9821");
System.out.println(testPredicate(list, (l) -> {
return l.length() > 3;
}));
} //消费型接口:Consumer<T> 有参数,无返回值类型的接口
public static void testConsumer(double money, Consumer<Double> con) {
con.accept(money);
} //函数型接口:Function<T,R> 输入一个类型得参数,输出一个类型得参数,当然两种类型可以一致
public static String testFunction(String str, Function<String, String> fun) {
return fun.apply(str);
} //供给型接口:Supplier<T> 只有产出,没人输入,就是只有返回值,没有入参
public static List<Integer> testSupplier(int num, Supplier<Integer> sup) {
List<Integer> list = new ArrayList<>(num);
for (int i = 0; i < num; i++) {
list.add(sup.get());
}
return list;
} //断言型接口:Predicate<T> 输入一个参数,输出一个boolean类型得返回值
public static List<String> testPredicate(List<String> list, Predicate<String> pre) {
List<String> strlist = new ArrayList<>();
for (String s : list) {
if (pre.test(s)) {
strlist.add(s);
}
}
return strlist;
}
}

2.3、方法引用和构造器

2.3.1、方法引用

import entity.Student;

import java.util.*;
import java.util.function.*; /**
* @author: wu linchun
* @time: 2021/8/16 14:26
* @description:
*/ public class TestLambda03 {
public static void main(String[] args) {
Student student = new Student("张三", 100, 20);
Supplier<String> stringSupplier = () -> student.getName();
System.out.println("姓名:" + stringSupplier.get()); //对象::实例方法名
Supplier<Integer> stringSupplier1 = student::getAge;
System.out.println("年龄:" + stringSupplier1.get()); List<Integer> list = Arrays.asList(1, 2, 4, 32, 23, 100, 32, 400, 20);
List<Integer> list1 = Arrays.asList(1, 2, 4, 32, 23, 100, 32, 400, 20);
Comparator<Integer> comparator = (x, y) ->
{
return Integer.compare(x, y);
};
//类::静态方法名
Comparator<Integer> comparator1 = Integer::compare;
Collections.sort(list, comparator);
Collections.sort(list1, comparator1);
for (int i : list) {
System.out.print(i + ",");
}
System.out.println();
for (int i : list1) {
System.out.print(i + ",");
} System.out.println();
BiPredicate<String, String> ff = (x, y) -> x.equals(y);
//类::实例方法名
BiPredicate<String, String> ff1 = String::equals;
System.out.println(ff.test("aa", "aa"));
System.out.println(ff.test("aa", "bb"));
System.out.println(ff1.test("aa", "aa"));
System.out.println(ff1.test("aa", "bb")); }
}

2.3.2、构造器引用

import entity.Student;

import java.util.function.Function;
import java.util.function.Supplier; /**
* @author: wu linchun
* @time: 2021/8/16 18:02
* @description:
*/ public class TestLambda05 {
public static void main(String[] args) {
Student student = new Student("张三", 100, 20);
Supplier<Student> supplier = () -> student;
Supplier<Student> supplier1 = Student::new;
//构造器引用
Function<String, Student> function = Student::new;
Function<Integer, Student> function1 = Student::new;
Student student1 = function.apply("李四");
Student student2 = function1.apply(20);
System.out.println(supplier.get());
System.out.println(supplier1.get());
System.out.println(student1);
System.out.println(student2);
}
}

2.3.3、数组引用

import java.util.function.Function;

/**
* @author: wu linchun
* @time: 2021/8/16 17:55
* @description:
*/ public class TestLambda04 {
public static void main(String[] args) {
Function<Integer, String[]> fun = (x) -> new String[x];
//数组引用:Type[]:new
Function<Integer, String[]> fun1 = String[]::new;
String[] s1 = fun.apply(10);
String[] s2 = fun1.apply(20);
System.out.println(s1.length);
System.out.println(s2.length);
}
}

3、Stream API

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

Stream流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,流讲的是计算!”

注意:

  • Stream 自己不会存储元素。
  • Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
  • Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

 Stream 的操作三个步骤

  • 创建 Stream:一个数据源(如:集合、数组),获取一个流
  • 中间操作:一个中间操作链,对数据源的数据进行处理
  • 终止操作:一个终止操作,执行中间操作链,并产生结果

3.1、stream API常用例子

import entity.Student;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream; /**
* @author: wu linchun
* @date: 2021/08/17/13:55
* @Description:
**/
public class TestLambdaStream01 {
public static void main(String[] args) {
Student s1 = new Student("张三", 20, 100);
Student s2 = new Student("李四", 22, 100);
Student s3 = new Student("王五", 23, 100);
Student s4 = new Student("赵六", 24, 100);
Student s5 = new Student("赵7", 19, 100);
Student s6 = new Student("赵8", 18, 100);
Student s7 = new Student("张三", 20, 100);
List<Student> list = Arrays.asList(s1, s2, s3, s4, s5, s6, s7); //filter:从流中排除某些元素
Stream<Student> studentStreams = list.stream().filter(e -> {
return e.getAge() <= 20;
});
list.forEach(System.out::print);
System.out.println();
studentStreams.forEach(System.out::print);
System.out.println(); //limit(n):截断流,使元素不超过给定的数量n
Stream<Student> studentStream01 = list.stream().limit(2);
studentStream01.forEach(System.out::print);
System.out.println(); //skip(n):跳过前n个元素
Stream<Student> studentStream02 = list.stream().skip(3);
studentStream02.forEach(System.out::print);
System.out.println(); //distinct:去重重复的元素
Stream<Student> studentStream03 = list.stream().distinct();
studentStream03.forEach(System.out::print);
System.out.println(); //stream转list collect(Collectors.toList())
List<Student> studentList = list.stream().limit(3).collect(Collectors.toList());
studentList.forEach(System.out::print);
System.out.println(); //数组[]转stream:数组创建流
Student[] students = {s1, s2, s3, s4, s5, s6, s7};
Stream<Student> studentStream04 = Arrays.stream(students);
studentStream04.forEach(System.out::print);
System.out.println(); //stream.of:值创建流
Stream<Student> studentStream05 = Stream.of(s1, s2, s3, s4, s5, s6, s7);
studentStream05.forEach(System.out::print);
System.out.println(); //stream无限流 如果不加限制则会无限输出
Stream<Integer> stream = Stream.iterate(0, e -> e + 2);
stream.limit(20).forEach(System.out::println); }
}

stream中内部迭代由stream API完成forEach(),这点是区别于外部迭代的。

//外部迭代
Iterator<Student> iterator = list.listIterator();
while (iterator.hasNext()) {
System.out.print(iterator.next());
}

3.2、stream映射

3.2.1、map

map可以用来接收lambda表达式,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream; /**
* @author: wu linchun
* @time: 2021/8/18 21:05
* @description:
*/ public class TestLambda06 {
public static void main(String[] args) {
// map
List<String> list = Arrays.asList("aaa", "bbb", "vvv", "Eva", "rrr");
list.stream().map(s -> s.toUpperCase()).forEach(System.out::println);
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); Stream<Stream<Character>> stream = list.stream().map(TestLambda06::filterCharacter);
//stream只能被使用一次,如果连续执行一个对象的stream 就报错了
//stream.forEach(System.out::print);
//stream.close();
System.out.println();
stream.forEach(s -> s.forEach(System.out::print));
} public static Stream<Character> filterCharacter(String str) {
List<Character> list = new ArrayList<>();
for (Character c : str.toCharArray()) {
list.add(c);
}
return list.stream();
}
}

3.2.2、flatMap

flatMap可以接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream; /**
* @author: wu linchun
* @time: 2021/8/19 22:19
* @description:
*/ public class TestLambda07 {
public static void main(String[] args) {
List<String> list = Arrays.asList("asawaxgd", "qw", "rthaacxdf", "paaaolmjh", "laalik", "aaq", "e", "ww");
Stream<Character> stream = list.stream().flatMap(TestLambda07::filterStream);
stream.forEach(System.out::println);
} public static Stream<Character> filterStream(String str) {
List<Character> list = new ArrayList<>();
for (Character c : str.toCharArray()) {
if (c.equals('a')) {
list.add(c);
}
}
return list.stream();
}
}

简单来说,map和flatMap是对数组流的拆解和合并,具体应用为对数组进行分类再输出。

3.3、stream排序与查找

  • allMatch:检查是否匹配所有元素。
  • anyMatch:检查是否至少匹配一个元素。
  • noneMatch:检查是否没有匹配所有元素。
  • findFirst:返回第一个元素。
  • findAny:返回当前流中的任意一个元素(如果是串行并且数据量较少的情况下,是会返回第一个元素。但是如果是并行的话,就不一定是返回第一个,而是可能是随机的。
  • count:返回流中元素的总个数。
  • max:返回流中最大值。
  • min:返回流中最小值。
import entity.Teacher;
import enums.Status; import java.util.Arrays;
import java.util.List;
import java.util.Optional; /**
* @author: wu linchun
* @time: 2021/8/20 9:59
* @description:
*/ public class TestLambda09 {
public static void main(String[] args) {
List<Teacher> list = Arrays.asList(
new Teacher("n1", 20, Status.FREE.getContent()),
new Teacher("n2", 21, Status.BUSY.getContent()),
new Teacher("n3", 22, Status.FREE.getContent()),
new Teacher("n4", 24, Status.BUSY.getContent()),
new Teacher("n5", 23, Status.FREE.getContent()),
new Teacher("n6", 20, Status.FREE.getContent()));
//allMatch:检查是否匹配所有元素
boolean b1 = list.stream().allMatch((e) -> e.getStatus().equals(Status.BUSY.getContent()));
//anyMatch:检查是否至少匹配一个元素
boolean b2 = list.stream().anyMatch((e) -> e.getStatus().equals(Status.BUSY.getContent()));
//noneMatch:检查是否没有匹配所有元素
boolean b3 = list.stream().noneMatch((e) -> e.getStatus().equals(Status.VOCATION.getContent()));
//findFirst:返回第一个元素
Optional<Teacher> opf = list.stream().findFirst();
//findAny:返回当前流中的任意一个元素(如果是串行并且数据量较少的情况下,是会返回第一个元素。
//但是如果是并行的话,就不一定是返回第一个,而是可能是随机的
Optional<Teacher> opn = list.stream().findAny();
Optional<Teacher> opn1 = list.parallelStream().findAny();
//count:返回流中元素的总个数
long count = list.stream().count();
//max:返回流中最大值
Optional<Teacher> opm = list.stream().max((e1, e2) -> {
return Integer.compare(e1.getAge(), e2.getAge());
});
//min:返回流中最小值
Optional<Teacher> opm1 = list.stream().min((e1, e2) -> {
return Integer.compare(e1.getAge(), e2.getAge());
});
System.out.println(b1);
System.out.println(b2);
System.out.println(b3);
System.out.println(opf.get());
System.out.println(opn.get());
System.out.println(opn1.get());
System.out.println(count);
System.out.println(opm.get());
System.out.println(opm1.get());
}
}

3.4、map-reduce

reduce:归约,可将流中的元素反复结合起来得到一个值。

import entity.Student;

import java.util.Arrays;
import java.util.List;
import java.util.Optional; /**
* @author: wu linchun
* @time: 2021/8/20 22:17
* @description:
*/ public class TestLambda11 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
//reduce:归约,相当于 0 +1+2+3+4+5+6+7+8+9+10=55
int num = list.stream().reduce(0, (x, y) -> x + y);
System.out.println(num);
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
List<Student> studentList = Arrays.asList(
new Student("张三", 20, 100),
new Student("李四", 21, 61),
new Student("王五", 16, 40),
new Student("赵六", 17, 77),
new Student("ttt", 22, 90),
new Student("sss", 19, 88)
);
//map-reduce: map为获取list中每个对象的指定元素,reduce会操作这些元素进行一些操作
Optional<Integer> op = studentList.stream().map(Student::getScore).reduce(Integer::sum);
System.out.println(op.get());
}
}

3.5、collection

collection:收集,即把stream流转为其他形式,属于stream流的终止操作。

import entity.Student;

import java.util.*;
import java.util.stream.Collectors; /**
* @author: wu linchun
* @time: 2021/8/21 10:22
* @description:
*/ public class TestLambda12 {
public static void main(String[] args) {
List<Student> studentList = Arrays.asList(
new Student("张三", 20, 100),
new Student("李四", 21, 61),
new Student("王五", 16, 40),
new Student("赵六", 17, 77),
new Student("ttt", 22, 90),
new Student("sss", 19, 90)
);
//collect:计算总数
long count = studentList.stream().collect(Collectors.counting());
//collect:计算平均值
double averageAge = studentList.stream().collect(Collectors.averagingDouble(Student::getAge));
//collect:求和
double sumGrade = studentList.stream().collect(Collectors.summingDouble(Student::getScore));
//collect:分组,相同的成绩为一组
Map<Integer, Map<String, List<Student>>> map = studentList.stream().collect(Collectors.groupingBy(Student::getScore, Collectors.groupingBy((e) -> {
switch (e.getScore() / 10) {
case 10:
return "A";
case 9:
return "A";
case 8:
return "B";
case 7:
return "C";
default:
return "D";
}
})));
//collect:分区 按年龄是否大于20进行分区
Map<Boolean, List<Student>> map1 = studentList.stream().collect(Collectors.partitioningBy((e) ->
e.getAge() > 20));
//collect:找最大值
Optional<Student> op = studentList.stream().collect(Collectors.maxBy((e1, e2) -> {
return Double.compare(e1.getScore(), e2.getScore());
}));
//collect:最小值
Optional<Student> op1 = studentList.stream().collect(Collectors.minBy((e1, e2) -> {
return Double.compare(e1.getScore(), e2.getScore());
}));
//collect:转为list
List<String> nameList = studentList.stream().map(Student::getName).collect(Collectors.toList());
//collect:转为set
Set<String> nameSet = studentList.stream().map(Student::getName).collect(Collectors.toSet());
//collect:转为hashset Collectors.joining(分隔符,前缀,后缀)
HashSet<String> nameHs = studentList.stream().map(Student::getName).collect(Collectors.toCollection(HashSet::new));
String nameStr = studentList.stream().map(Student::getName).collect(Collectors.joining(",", "<-", "->"));
//collect:汇总 最大值,最小值,平均值,总数,总和
DoubleSummaryStatistics dss = studentList.stream().collect(Collectors.summarizingDouble(Student::getAge));
System.out.println(count);
System.out.println(averageAge);
System.out.println(sumGrade);
for (Map.Entry<Integer, Map<String, List<Student>>> entry : map.entrySet()) {
System.out.println(entry.getKey() + "——>" + entry.getValue());
}
System.out.println("~~~~~~~~~~~~~~~~~~~");
for (Map.Entry<Boolean, List<Student>> entry : map1.entrySet()) {
System.out.println(entry.getKey() + "——>" + entry.getValue());
}
System.out.println(op.get());
System.out.println(op1.get());
System.out.println(nameList.toString());
System.out.println(nameSet);
System.out.println(nameHs);
System.out.println(nameStr);
System.out.println(dss.getMax() + " " + dss.getMin() + " " + dss.getAverage() + " " + dss.getCount() + " " + dss.getSum());
}
}

3.6、steamAPI练习

import com.sun.org.apache.bcel.internal.generic.ARETURN;
import entity.Student;
import entity.Trader;
import entity.Transaction;
import org.junit.Before;
import org.junit.Test; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors; /**
* @author: wu linchun
* @time: 2021/8/21 11:38
* @description:
*/ public class MyPractise {
List<Transaction> transactions = null; @Before
public void before() {
Trader raoul = new Trader("Raoul", "Cambridge");
Trader mario = new Trader("Mario", "Milan");
Trader alan = new Trader("Alan", "Cambridge");
Trader brian = new Trader("Brian", "Cambridge"); transactions = Arrays.asList(
new Transaction(brian, 2011, 300),
new Transaction(raoul, 2012, 1000),
new Transaction(raoul, 2011, 400),
new Transaction(mario, 2012, 710),
new Transaction(mario, 2012, 700),
new Transaction(alan, 2012, 950)
);
} @Test
public void ex1() {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.stream().map((e) -> {
return e * e;
}).forEach(System.out::println);
System.out.println(list.stream().collect(Collectors.counting()));
} @Test
public void ex2() {
List<Student> studentList = Arrays.asList(
new Student("张三", 20, 100),
new Student("李四", 21, 61),
new Student("王五", 16, 40),
new Student("赵六", 17, 77),
new Student("ttt", 22, 90),
new Student("sss", 19, 90)
);
studentList.stream().filter(e -> {
return e.getScore() >= 90;
}).sorted((e1, e2) -> {
return -Integer.compare(e1.getScore(), e2.getScore());
}).forEach(System.out::println);
} //1. 找出2011年发生的所有交易, 并按交易额排序(从低到高)
@Test
public void ex3() {
transactions.stream().filter((e) -> e.getYear() == 2011).sorted((e1, e2) -> {
return Integer.compare(e1.getValue(), e2.getValue());
}).forEach(System.out::println);
} //2. 交易员都在哪些不同的城市工作过?
@Test
public void ex4() {
transactions.stream().map((e) -> {
return e.getTrader().getCity();
}).distinct().forEach(System.out::println);
} //3. 查找所有来自剑桥的交易员,并按姓名排序
@Test
public void ex5() {
transactions.stream().filter((e) -> {
return e.getTrader().getCity().equals("Cambridge");
}).sorted((n1, n2) -> {
return n1.getTrader().getName().compareTo(n2.getTrader().getName());
}).forEach(System.out::println);
} //4. 返回所有交易员的姓名字符串,按字母顺序排序
@Test
public void ex6() {
System.out.println(transactions.stream().map((e) -> e.getTrader().getName()).sorted((e1, e2) -> {
return e1.compareTo(e2);
}).collect(Collectors.joining(",")));
} //5. 有没有交易员是在米兰工作的?
@Test
public void ex7() {
System.out.println(transactions.stream().map((e) -> e.getTrader().getCity()).anyMatch((e) -> {
return e.equals("Milan");
}));
} //6. 打印生活在剑桥的交易员的所有交易额
@Test
public void ex8() {
System.out.println(transactions.stream().filter((e) -> e.getTrader().getCity().equals("Cambridge")).collect(Collectors.summingInt((e) -> e.getValue())));
} //7. 所有交易中,最高的交易额是多少
@Test
public void ex9() {
System.out.println(transactions.stream().collect(Collectors.maxBy((e1, e2) -> {
return Integer.compare(e1.getValue(), e2.getValue());
})).get());
} //8. 找到交易额最小的交易
@Test
public void ex10() {
System.out.println(transactions.stream().collect(Collectors.minBy((e1, e2) -> {
return Integer.compare(e1.getValue(), e2.getValue());
})));
}
}

4、并行流

并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。java8对并行流进行了优化,封装了fork/join框架。在java8中,Stream API 可以声明性地通过 parallel() 与
sequential() 在并行流与顺序流之间进行切换。

4.1、fork/join框架

fork/join框架会把大的任务拆分成一个个小任务,再分别把每个小任务分配到不同的线程中,形成一个个线程队列。

不过fork/join和传统的线程池有所区别的是,fork/join框架新增了“工作窃取”模式。执行快的线程在其当前线程队列里面的任务执行完成后,会随机从其他还没有执行完的线程队列队尾“偷”一个放到自己的线程队列中执行(自己没有任务了,就去偷别人的,最大限度的利用cpu)。

fork/join框架只在数据足够多的时候才会体现出其优越性,因为任务拆分是需要消耗时间的,因此如果数据不多,那与顺序流单线程相比没有太多优势。

4.2、顺序流与并行流比较

从0加到1000000000L

1、顺序流

public class TestLambda13 {
public static void main(String[] args) {
Instant start1 = Instant.now();
long sum = 0;
//从0累加到1000000000L
for (int i = 0; i <= 1000000000L; i++) {
sum += i;
}
System.out.println(sum);
Instant end1 = Instant.now();
System.out.println("顺序流耗费时间:" + Duration.between(start1, end1).toMillis());
}
}

可以看到顺序流,cpu执行一个线程去处理,对cpu的利用率不高。

2、并行流

public class TestLambda13 {
public static void main(String[] args) {
Instant start = Instant.now();
//从0累加到1000000000L
System.out.println(LongStream.rangeClosed(0, 1000000000L).parallel().reduce(0, Long::sum));
Instant end = Instant.now();
System.out.println("并行流耗费时间:" + Duration.between(start, end).toMillis());
}
}

可以看到并行流,会最大化的去利用cpu。

5、接口中的默认方法

在java8之前,接口Interface里面是只能写方法体,不能写方法实现的。但在java8之后,允许在接口中写默认(default)方法的实现。

如下:

public interface MyInterface {
default String getXXX() {
return "xxx";
} default String getYYY() {
return "yyy";
}
}

在接口的实现方法中,如果不重写接口中的默认方法,那么就会直接使用接口中已经写好的默认方法。

public class MyInterfaceImpl implements MyInterface {
@Override
public String getXXX() {
return MyInterface.super.getXXX();
} @Override
public String getYYY() {
return MyInterface.super.getYYY();
}
}
public class TestLambda14 {
public static void main(String[] args) {
System.out.println(new MyInterfaceImpl().getXXX());
System.out.println(new MyInterfaceImpl().getYYY());
}
}

当然,如果在接口实现类中重写了接口的默认方法,那么接口中的相应方法会被忽略。

public class MyInterfaceImpl implements MyInterface {
@Override
public String getXXX() {
return "ZZZ";
} @Override
public String getYYY() {
return "AAA";
}
}

6、新时间日期api

java8以后的时间日期api是线程安全的,在java8之前的时间日期api是非线程安全的。

LocalDate、LocalTime、LocalDateTime 类的实例是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。

Instant时间戳用于“时间戳”的运算,它是以Unix元年(传统的设定为UTC时区1970年1月1日午夜时分)开始所经历的描述进行运算。

  • Duration:用于计算两个“时间”间隔。
  • Period:用于计算两个“日期”间隔。

DateTimeFormatter用于日期格式化。

public class TestLambda15 {
public static void main(String[] args) {
//获取当前日期时间
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt); //自定义日期时间
LocalDateTime ldt1 = LocalDateTime.of(2020, 10, 20, 12, 25, 33, 12);
System.out.println(ldt1); //年月日加一
LocalDateTime ldt2 = ldt1.plusYears(1).plusMonths(1).plusDays(1).plusHours(1);
System.out.println(ldt2); //获取当前时间戳
Instant start = Instant.now();
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
Instant end = Instant.now();
//Duration:计算两个“时间”之间的间隔
System.out.println(Duration.between(start, end).toMillis());
//Period:计算两个“日期”之间的间隔
LocalDate ld1 = LocalDate.of(2015, 8, 12);
LocalDate ld2 = LocalDate.now();
System.out.println(Period.between(ld1, ld2).getYears()); //格式化时间日期
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
System.out.println(dateTimeFormatter.format(ldt)); }
}

7、重复注解与类型注解

7.1、重复注解

在java8中新增了一个注解@Repeatable,允许同一个注解在同一个地方被使用多次。

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
//RUNTIME:允许这个注解被反射,注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {
MyAnnotation[] value();
}
@Repeatable(MyAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
//RUNTIME:允许这个注解被反射,注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value();
}
import annotation.MyAnnotation;
import annotation.MyAnnotation_01; import java.lang.reflect.Method; /**
* @author: wu linchun
* @time: 2021/8/21 22:37
* @description:
*/ public class TestLambda16 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
Class c = Class.forName("TestLambda16");
Method method1 = c.getMethod("showTwo");
MyAnnotation[] myAnnotation1 = method1.getAnnotationsByType(MyAnnotation.class);
for (MyAnnotation myAnnotation : myAnnotation1) {
System.out.print(myAnnotation.value() + " ");
}
} @MyAnnotation("Hello")
@MyAnnotation("World")
public static void showTwo() {
}
}

7.2、类型注解

TYPE_PARAMETER即类型注解,可以注解各种java类型(int,String,数组......)。

@Repeatable(MyAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE,TYPE_PARAMETER})
//RUNTIME:允许这个注解被反射,注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value();
}
import annotation.MyAnnotation;
import annotation.MyAnnotation_01; import java.lang.annotation.Annotation;
import java.lang.reflect.Method; /**
* @author: wu linchun
* @time: 2021/8/21 22:37
* @description:
*/ public class TestLambda16 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
Class c = Class.forName("TestLambda16");
Method method1 = c.getMethod("showTwo", String.class);
//获取方法注解
MyAnnotation[] myAnnotation1 = method1.getAnnotationsByType(MyAnnotation.class);
for (MyAnnotation myAnnotation : myAnnotation1) {
System.out.print(myAnnotation.value() + " ");
}
System.out.println();
//获取参数注解
Annotation[][] myAnnotation2 = method1.getParameterAnnotations();
System.out.println(myAnnotation2[0][0]); } @MyAnnotation("Hello")
@MyAnnotation("World")
public static void showTwo(@MyAnnotation("123") String num) { }
}

8、总结

就我在工作中的实际使用而言,java8中最有用的是stream流和新时间日期api。但时间日期api通常会在实际开发中被单独封装成一个util工具类,需要格式转换还是计算时间直接调用工具类中的相应方法就行了。唯一用的比较多的是stream api,stream api结合Lambda表达式可以极大的简化代码。常见的像filter、map、sort、limit等可以很灵活的处理list中的数据。尤其是在后端开发中会涉及调取很多第三方接口,用stream api处理第三方接口的数据会非常方便。对于一些查库操作,使用stream api可以很好的减少查库次数,降低数据库io。其实就是先多查一些数据,然后用stream api处理。可以避免一些循环查询的情况,提高程序执行效率。

9、参考资料

java8新特性学习笔记的更多相关文章

  1. java8 新特性学习笔记

    Java8新特性 学习笔记 1主要内容 Lambda 表达式 函数式接口 方法引用与构造器引用 Stream API 接口中的默认方法与静态方法 新时间日期 API 其他新特性 2 简洁 速度更快 修 ...

  2. java8新特性学习笔记(二) 使用流(各种API)

    筛选和切片 用谓词筛选,筛选出各个不相同的元素,忽略流中的头几个元素,或将流截断至指定长度 用谓词筛选 Stream接口支持filter方法,该操作接受一个谓词(返回一个boolean的函数) 作为参 ...

  3. java8新特性学习笔记(二) 流的相关思想

    流是什么 流是Java API的新成员,他允许你以声明的方式处理数据集合,就现在来说,可以把他们看成遍历数据集合的高级迭代器.此外,流还可以透明地并行处理,你无须写任何多线程代码. 下面例子是新老AP ...

  4. Java8新特性学习笔记(一) Lambda表达式

    没有用Lambda表达式的写法: Comparator<Transaction> byYear = new Comparator<Transaction>() { @Overr ...

  5. java8新特性学习笔记链接

    https://blog.csdn.net/yitian_66/article/details/81010434

  6. Java8 新特性学习 Lambda表达式 和 Stream 用法案例

    Java8 新特性学习 Lambda表达式 和 Stream 用法案例 学习参考文章: https://www.cnblogs.com/coprince/p/8692972.html 1.使用lamb ...

  7. java8新特性学习:函数式接口

    本文概要 什么是函数式接口? 如何定义函数式接口? 常用的函数式接口 函数式接口语法注意事项 总结 1. 什么是函数式接口? 函数式接口其实本质上还是一个接口,但是它是一种特殊的接口:SAM类型的接口 ...

  8. java8新特性学习1

    java8增加了不少新特性,下面就一些常见的新特性进行学习... 1.接口中的方法 2.函数式接口 3.Lambda表达式 4.java8内置的四大核心函数式接口 5.方法引用和构造器引用 6.Str ...

  9. java8新特性学习:stream与lambda

    Streams api 对 Stream 的使用就是实现一个 filter-map-reduce 过程,产生一个最终结果,或者导致一个副作用(side effect). 流的操作类型分为两种: Int ...

  10. Java8 新特性学习

    摘自:https://blog.csdn.net/shuaicihai/article/details/72615495 Lambda 表达式 Lambda 是一个匿名函数,我们可以把 Lambda ...

随机推荐

  1. TomCat之安装

    TomCat 之安装(伪分布式版本) 本次安装是使用的伪分布式的安装(即一台机器安装两个tomcat) 1.通过scp导入tomcat安装包 2.解压缩成俩个文件 3.修改第一个tomcat的配置文件 ...

  2. win10操作系统下Android环境配置

    Windows命令行调试unity(Android)应用环境变量配置准备步骤:先下载好我们需要的Android SDK和JDK. Android SDK推荐地址:http://tools.androi ...

  3. SQL---ltrim()和rtrim()函数的使用

    背景 去除字符串首尾空格大家肯定第一个想到trim()函数,不过在sqlserver中是没有这个函数的,却而代之的是ltrim()和rtrim()两个函数. 看到名字所有人都 知道做什么用的了,ltr ...

  4. 【神经网络】softmax回归

    前言 softmax回归为一种分类模型. 基本原理 由于softmax回归也是一种线性叠加算法,且需要输出离散值. 很自然地想到,可以取值最大的输出为置信输出.更进一步想到,如果有三个人A.B.C分别 ...

  5. 谷歌浏览器xpath获取网页按钮路径

    谷歌浏览器打开要获取的页面按下F12打开开发者工具 点击最左边的元素选择器,高亮后光标移动到对应元素框(这里只选择里层的元素,如这里要选到input级别) 点击后下方HTML会高亮显示,鼠标移动上去右 ...

  6. VUE2 学习(推荐直接学习VUE3)

    概念区分: 前端框架:Vue.AngularJS.React 界面模板:Bootstrap.easyUI.adminlte 学习地址: b站:https://space.bilibili.com/39 ...

  7. Java安全之Resin2内存马

    Java安全之Resin2内存马 环境 resin2.1.17 添加Filter分析 依然是web.xml注册一个filter,debug进去看注册流程 debug dofilter逻辑时看到如下代码 ...

  8. 记一次线上频繁fullGc的排查解决过程

    发生背景 最近上线的一个项目几乎全是查询业务,并且都是大表的慢查询,sql优化是做了一轮又一轮,前几天用户反馈页面加载过慢还时不时的会timeout,但是我们把对应的sql都优化一遍过后,前台响应还是 ...

  9. 题解合集 (update on 11.5)

    收录已发布的题解 按发布时间排序. 部分可能与我的其他文章有重复捏 qwq . AtCoder for Chinese: Link ZHOJ: Link 洛谷 \(1\sim 5\) : [题解]CF ...

  10. 如何在 .NET MAUI 中加载 json 文件?

    引言: 按core传统方式添加 AddJsonFile("appsettings.json") 在windows平台和ssr工作正常,但是在 ios 和 android 无法用这种 ...