目录
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、参考资料?
|