http://blog.itpub.net/9399028/viewspace-2674082/ 新特性
1.Lambda表达式
/**
* Lambda表达式 针对函数式接口,接口中只有一个方法时
*/
public class LambdaTest {
@Test
public void test1() {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("非lambda写法");
}
};
// -> lambda操作符
Runnable r2 = (() -> {
System.out.println("lambda写法");
});
//
// -> lambda操作符 省去 最外层的()
Runnable r3 = () -> System.out.println("lambda写法");
r1.run();
r2.run();
}
@Test
public void test2() {
//比较器
Comparator<Integer> com = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1-o2;
}
};
Comparator<Integer> com1 = (o1, o2) -> {
return o1 - o2;
};
//省去 {} 省去return 原理 函数式接口,内部本就知道是否有返回值
Comparator<Integer> com2 = (o1, o2) -> o1 - o2;
// //方法引用 更简洁
Comparator<Integer> com2 = Integer :: compare;
}
}
lambda表达式的使用
1. 举例 (o1,o2) -> Integer.compare(o1,o2)
2. 格式
- ->:lambda操作符或箭头操作符
- ->:左边 lambda形参列表 (接口中抽象方法的形参)
- ->:右边 lambda体 (重写的抽象方法的方法体)
3. 使用(分为6种情况)
其实分为:
左边()是否可以省去,
右边{}是否可以省去
1.无参,无返回值,
2.只有一个参数,
3.两个以上参数,
4.方法体两条以上,
5.方法体只有一条。//语法格式1 无参 无返回值
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("非lambda写法");
}
};
// -> lambda操作符
Runnable r2 = () -> System.out.println("lambda写法");
//语法格式二: 需要一个参数 没有返回值
Consumer<String> con = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con.accept("con");
Consumer<String> con1 = (String s) -> System.out.println(s);
con1.accept("con1");
4. lambda表达式的本质:作为函数式接口的实例 (函数式接口)
2.函数式(Functional)接口
- 如果一个接口种只声明了一个抽象方法,就称为函数式接口Runable CompareTo
- 可以通过Lambda表达式来创建该接口的对象。(若Lambda表达式抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明)。
- 我们可以在一个接口上使用@Functionallnterface注解,这样做可以检查它是否是一个函数式接口。同时javadoc也会包含一条声明说明这个接口是一个函数式接口。
- 在java.util.function包下定义了Java8的丰富的函数式接口 ```java
@FunctionalInterface
public interface MyInterface {
void method();
}
<a name="9KXgW"></a>
### 1.内置四大核心函数式接口
![image.png](https://cdn.nlark.com/yuque/0/2021/png/21994224/1625211466837-6ec59516-8e13-45d5-bed7-5461abe7c06e.png#align=left&display=inline&height=250&margin=%5Bobject%20Object%5D&name=image.png&originHeight=286&originWidth=597&size=129371&status=done&style=none&width=521)
```java
//示例
public class FunctionTest {
@Test
public void test1() {
happyTime(66.66,(d) -> System.out.println("消费"+d));
}
public void happyTime(double money, Consumer<Double> consumer) {
consumer.accept(money);
}
}
//断定型接口示例
@Test
public void test2() {
List<String> newList = filterString(Arrays.asList("123456","156","486","DASD","DASDW"), s -> s.contains("A"));
newList.forEach(System.out::println);
}
public List<String> filterString(List<String> stringList, Predicate<String> predicate){
List<String> filter = new ArrayList<>();
for (String s : stringList) {
if (predicate.test(s)) {
filter.add(s);
}
}
return filter;
}
2.其他接口
3.方法引用与构造器引用
3.1介绍
- 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
- 方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。
- 要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!
- 格式:使用操作符“::”将类(或对象)与方法名分隔开来。
如下三种主要使用情况:
- 对象:∵实例方法名
- 类:静态方法名
-
3.2使用情景
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用(引用别人的方法)!
方法引用使用的要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同!(针对情况a,b)3.3使用格式
3.4示例
对象::示例方法名
//情况一 对象::实例方法
//consumer中的void accept(T t)
//PrintStream 中void println(T t)
@Test
public void test1() {
Consumer<String> con1 = str -> System.out.println(str);
con1.accept("输出");
System.out.println("********************");
PrintStream ps = System.out;
Consumer<String> con2 = ps::println;
con2.accept("方法引用输出");
}
//supplier 中 T get()
//Employee中String getName()
@Test
public void test2() {
Employee employee = EmployeeData.getEmployees().get(0);
Supplier<String> sup1 = () -> employee.getName() ;
System.out.println(sup1.get());
//方法引用
Supplier<String> sup2 = employee::getName;
System.out.println(sup2.get());
}
类::静态方法
//情况二: 类::静态方法
//Comparator中 compare(t1,t2)
//Integer 中compare(t1,t2)
@Test
public void test3() {
Comparator<Integer> com1 = (c1,c2) -> Integer.compare(c1,c2);
com1.compare(12,2);
//方法引用
Comparator<Integer> com2 = Integer::compare;
com2.compare(27,93);
}
类::实例方法
```java //情况三: 类::实例方法 难 传入的参数调用类中的方法 //Comparator compare(T t1,T t2) //String compareTo(T t2) @Test public void test4() { Comparator
com1 = (s1,s2) -> s1.compareTo(s2); System.out.println(com1.compare(“abc”,”adb”)); System.out.println(“**“); Comparator com2 = String::compareTo; System.out.println(com2.compare(“abc”,”abd”)); } //BigPredicate中 boolean test(T t1,T t2); //String中的boolean t1.equals(t2) @Test public void test5() { BiPredicate
pre1 = (s1,s2) -> s1.equals(s2); System.out.println(pre1.test(“avc”,”avc”)); System.out.println(“*“); BiPredicate pre2 = String::equals; System.out.println(pre2.test(“avc”,”avc”)); } //Function 中R apply(T t) //Employee String getName(); @Test public void test7() { Function
f1 = e -> e.getName(); System.out.println(f1.apply( EmployeeData.getEmployees().get(0))); System.out.println(“*“); Function f2 = Employee::getName; System.out.println(f2.apply( EmployeeData.getEmployees().get(0))); }
<a name="Dj7zr"></a>
### 3.5构造器引用
和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致<br />抽象方法的返回值类型即为构造器所属类的类型
```java
//构造器引用
//Supplier中T get()
//空参构造器
@Test
public void test1() {
Supplier<Employee> sup1 = () -> new Employee();
Employee e1 = sup1.get();
Supplier<Employee> sup2 = Employee::new;
Employee e2 = sup2.get();
}
//Function 中R apply(T t)
@Test
public void test2() {
Function<Integer,Employee> func1 = id -> new Employee(id);
Employee e1 = func1.apply(1);
Function<Integer,Employee> func2 = Employee::new;
Employee e2 = func2.apply(2);
}
//BiFunction 中R apply(T t,R r)
@Test
public void test3() {
BiFunction<Integer,String,Employee> fun1 = (id,name) -> new Employee(id,name);
Employee e1 = fun1.apply(1,"a");
BiFunction<Integer,String,Employee> fun2 = Employee::new;
Employee e2 = fun2.apply(2,"b");
}
3.6数组引用
数组看作是类 写法和构造器相似一致
//数组引用
//Function中的R apply(T t)
@Test
public void test4() {
//返回指定长度数组
Function<Integer,String[]> func1 = length -> new String[length];
Function<Integer,String[]> func2 = String[]::new;
}
4.强大的Stream API
使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。
Collection是一种静态的内存数据结构,Stream是有关计算的。
Stream不会改变源对象,相反,会返回一个持有结果的新的Stream
必须有终止操作,否则不会执行中间链
1.四种创建方式:
- 通过集合
- 通过数组
- 通过Stream的of()方法
创建无限流
/**
* stream关注对数据的运算
* 操作是延迟执行的, 只有执行终止操作 中间操作才会执行
* 终止操作后,不可再执行中间操作链 需要再新建stream
* 实例化
* 一系列中间操作 一条链
* 终止操作
*/
public class StreamAPITest {
//创建Stream方式一 通过集合
@Test
public void test1() {
List<Employee> employees = EmployeeData.getEmployees();
// default Stream<E> stream(); 返回一个顺序流
Stream<Employee> stream = employees.stream();
//default Stream<E> parallelStream(); 返回一个并行流
Stream<Employee> employeeStream = employees.parallelStream();
}
//方式二: 通过数组
@Test
public void test2() {
// Arrays.stream(T[] array)
Integer[] a = {1,2,3,4,5};
Stream<Integer> stream = Arrays.stream(a);
//自定义数组
Employee e1 = new Employee(1001,"张叁",23,3399);
Employee e2 = new Employee(1002,"李肆",24,9444);
Employee e3 = new Employee(1003,"王伍",25,5555);
Employee e4 = new Employee(1004,"赵陆",26,96435);
Employee e5 = new Employee(1005,"周柒",27,77777);
Employee[] arr1 = new Employee[]{e1,e2,e3,e4,e5};
Stream<Employee> stream1 = Arrays.stream(arr1);
}
//方式三 通过Stream的of()方法
@Test
public void test3() {
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6);
}
//方式四 创建无限流
@Test
public void test4() {
// 迭代
// public static<T> Stream<T> iterate(final T seed,final Unaryoperator<T> f)
//遍历前10各偶数
Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
// 生成
// public static<T> Stream<T> generate(Supplier<T> s)
Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
2.stream的中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,篙则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。
1.筛选和切片
//1-筛选切片
@Test
public void test1() {
List<Employee> employees = EmployeeData.getEmployees();
//查询员工表中工资大于7000的
//执行终止操作后stream流会被关闭 无法再次使用
List<Object> objects = Arrays.asList(employees.stream().filter(t -> t.getSalary() > 7000).toArray());
System.out.println(objects);
// filter(Predicate p)——接收Lambda ,从流中排除某些元素。
// limit(n)——截断流,使其元素不超过给定数是。
employees.stream().limit(3).forEach(System.out::println);
System.out.println("===========");
// skip(n)——跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补
employees.stream().skip(3).forEach(System.out::println);
System.out.println("===========");
// distinct()——筛选,通过流所生成元素的hashCode()和equals()去除重复元素
employees.stream().distinct().forEach(System.out::println);
}
2.映射
//2-映射
@Test
public void test2() {
// map(Function f) 接收一个函数作为参数,将元素转换成其他形式获取提取信息,该函数会被应用到每个元素上,并将其映射成一个新元素
List<String> strings = Arrays.asList("c", "s", "aa", "dd");
strings.stream().map(String::toUpperCase).forEach(System.out::println);
// 可以筛选元素中的某一条属性
List<Employee> employees = EmployeeData.getEmployees();
List<String> names = employees.stream().map(Employee::getName).collect(Collectors.toList());
System.out.println(names);
// 示例1获取员工姓名长度大于2的名称
Stream<Employee> employeeStream = employees.stream().filter(Employee::nameLength);
List<String> namess = employeeStream.map(Employee::getName).collect(Collectors.toList());
System.out.println(namess);
System.out.println("===========");
// 示例二
// 此map方法将解析后的元素作为整体存入stream流中
Stream<Stream<Character>> streamStream = strings.stream().map(StreamAPITest2::fromStringToStream);
streamStream.forEach(s -> s.forEach(System.out::println));
System.out.println("=============");
// flatMap(function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
// 将处理后的stream流进一步解析 相当于平铺开
Stream<Character> characterStream = strings.stream().flatMap(StreamAPITest2::fromStringToStream);
characterStream.forEach(System.out::println);
}
// 将字符串中的多个字符构成的集合转换为对应的Stream的实例
public static Stream<Character> fromStringToStream(String str) {
ArrayList<Character> list =new ArrayList<>();
for (Character c : str.toCharArray()) {
list.add(c);
}
return list.stream();
}
3.排序
// 3.排序
@Test
public void test3() {
// sorted()自然排序
List<Integer> list = Arrays.asList(12,15,6,7,60,16);
List<Integer> collect = list.stream().sorted().collect(Collectors.toList());
System.out.println(collect);
System.out.println("===========");
// sorted(Comparator com)定制排序 需要传入比较器
List<Employee> employees = EmployeeData.getEmployees();
employees.stream().sorted(new MyComparator()).forEach(System.out::println);
// lambda表达式
employees.stream().sorted((e1,e2) -> (e2.getId() - e1.getId())).forEach(System.out::println);
}
3.stream的终止操作
1.匹配与查找
外部迭代 iterator
// 1-匹配与查找
@Test
public void test1() {
List<Employee> employees = EmployeeData.getEmployees();
// allMatch(Predicate p) -- 检查是否匹配所有元素
// 是否所有员工的年龄都大于18
boolean b = employees.stream().allMatch(e -> e.getAge() > 18);
System.out.println(b);
System.out.println("==============");
// anyMatch(Predicate p)- 检查是否至少匹配一个元素。
// 是否存在员工工资大于7000
boolean b1 = employees.stream().anyMatch(e -> e.getSalary() > 7000);
System.out.println(b1);
System.out.println("==============");
// noneMatch(Predicate p)一检查是否没有匹配的元素。
// 是否存在无姓员工
boolean b2 = employees.stream().noneMatch(e -> e.getName().startsWith("李"));
System.out.println(b2);
System.out.println("==============");
// findFirst-返回第一个元素
Optional<Employee> first = employees.stream().findFirst();
Employee employee = first.get();
System.out.println(employee);
System.out.println("==============");
// findAny- -返回当前流中的任意元素 并行流
Employee employee1 = employees.parallelStream().findAny().get();
System.out.println(employee1);
System.out.println("==============");
// count-返回流 中元素的总个数
long count = employees.stream().filter(e -> e.getSalary() > 7000).count();
System.out.println(count);
// max(Comparator c)一返回流中最大值
// 练习:返回最高的工资:
Optional<Employee> max = employees.stream().max((e1, e2) -> Double.compare(e1.getSalary(),e2.getSalary()));
System.out.println(max);
// min(Comparator c)一返回流中最小值
// 练习:返回最低_工资的员工
Optional<Double> min = employees.stream().map(Employee::getSalary).min(Double::compareTo);
System.out.println(min);
System.out.println("==============");
// forEach(Consumer c)- -内部迭代
employees.stream().forEach(System.out::println);
}
@Test
public void testtt() {
List<Employee> employees = EmployeeData.getEmployees();
for (int i =0;i<20;i++) {
Employee employee1 = employees.stream().findAny().get();
System.out.println(employee1);
}
}
2.归约
备注: map和 reduce 的连接通常称为map-reduce 模式,因Google
用它来进行网络搜索而出名。
// 2.归约
@Test
public void test2() {
// reducp(T identity, BinaryOperator)- - 可以将流中元素反复结合起来,得到一个值。返回一个T
// 练习1.计算1-10的自然数的和
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
// 第一个参数 初始值
Integer reduce = list.stream().reduce(1, Integer::sum);
System.out.println(reduce);
// reduce(BinaryOperator)一可以将流中元素反复结合起来, 得到一个值。返回Option<T>
// 练习2:计算公司所有员工工资的总和
List<Employee> employees = EmployeeData.getEmployees();
Optional<Double> reduce1 = employees.stream().map(Employee::getSalary).reduce(Double::sum);
System.out.println(reduce1);
System.out.println(reduce1.get());
}
3.收集
Collector接口中方法的实现决定了如何对流执行收集的操作(如收集到List、Set.Map)。
另外,Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,
具体方法与实例如下表:
// 3.收集
@Test
public void test3() {
List<Employee> employees = EmployeeData.getEmployees();
// collect(Collector c)将 流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
// 练习 查找工资大于7000的员工 存入list中
List<Employee> collect = employees.stream().filter(e -> e.getSalary() > 7000).collect(Collectors.toList());
collect.forEach(System.out::println);
}
5.Option类
●Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
●创建Optional类对象的方法:
➢Optional.of(T t): 创建一个Optional实例,t必须非空;
➢Optional.empty(): 创建一个空的 Optional实例
➢Optional.ofNullable(T t): t 可以为nullI
@Test
public void test1() {
Girl girl = new Girl();
girl = null;
//t 不能为空
Optional<Girl> optionalGirl = Optional.of(girl);
}
@Test
public void test2() {
Girl girl = new Girl();
// girl = null;
Optional<Girl> optionalGirl = Optional.ofNullable(girl);
System.out.println(optionalGirl);
}
●判断Optional容 器中是否包含对象:
➢boolean isPresent() :判断是否包含对象
➢void ifPresent(Consumer<? super T> consumer):如果有值,就执行Consumer
接口的实现代码,并且该值会作为参数传给它。
●获取Optional容 器的对象:
➢T get):如果调用对象包含值,返回该值,否则抛异常
➢T orElse(T other):如果有值则将其返回,否则返回指定的other对象。
➢T orElseGet(Supplier<? extends T> other) :如果有值则将其返回,否则返回由
Supplier接口实现提供的对象。
➢T orElse Throw(Supplier<? extends X> exceptionSupplier):如果有值则将其返
回,否则抛出由Supplier接口实现提供的异常。
@Test
public void test3() {
// Boy boy = new Boy();
// String girlName = getGirlName(boy);
// System.out.println(girlName);
Boy boy1 = new Boy();
System.out.println(getGirlName1(null));
}
//优化
public String getGirlName1(Boy boy) {
// 没有optional时
// if (null != boy) {
// Girl girl = boy.getGirl();
// if (null !=girl) {
// return girl.getName();
// }
// }
// return null;
// 使用optional
Optional<Boy> boyOptional = Optional.ofNullable(boy);
Boy boy1 = boyOptional.orElse(new Boy());
Optional<Girl> girlOptional = Optional.ofNullable(boy1.getGirl());
Girl girl = girlOptional.orElse(new Girl());
return girl.getName();
}
6.StringJoiner
StringJoiner是Java8新出的一个类,用于构造由分隔符分隔的字符序列,并可选择性地从提供的前缀开始和以提供的后缀结尾。
- java.lang.String
- java.lang.StringBuffer
- java.lang.StrungBuilder
三者共同之处:都是final类,不允许被继承,主要是从性能和安全性上考虑的,因为这几个类都是经常被使用着,且考虑到防止其中的参数被参数修改影响到其他的应用。
- StringBuffer是线程安全,可以不需要额外的同步用于多线程中;
- StringBuilder是非同步,运行于多线程中就需要使用着单独同步处理,但是速度就比StringBuffer快多了;
- StringBuffer与StringBuilder两者共同之处:可以通过append、indert进行字符串的操作。
- String实现了三个接口:Serializable、Comparable
、CarSequence - StringBuilder只实现了两个接口Serializable、CharSequence,相比之下String的实例可以通过compareTo方法进行比较,其他两个不可以。
示例:
```java StringJoiner sj = new StringJoiner(“:”, “[“, “]”); sj.add(“George”).add(“Sally”).add(“Fred”); String desiredString = sj.toString();
[George:Sally:Fred]
```java
package java.util;
public final class StringJoiner {
private final String prefix;//前缀
private final String delimiter;//间隔符
private final String suffix;//后缀
private StringBuilder value;//值
private String emptyValue;//空值
public StringJoiner(CharSequence delimiter) {
this(delimiter, "", "");//默认前缀和后缀为"",重载调用
}
public StringJoiner(CharSequence delimiter,
CharSequence prefix,
CharSequence suffix) {
//间隔符,前缀和后缀判断是否为null,null将抛出异常
Objects.requireNonNull(prefix, "The prefix must not be null");
Objects.requireNonNull(delimiter, "The delimiter must not be null");
Objects.requireNonNull(suffix, "The suffix must not be null");
// 成员变量赋值
this.prefix = prefix.toString();
this.delimiter = delimiter.toString();
this.suffix = suffix.toString();
this.emptyValue = this.prefix + this.suffix;//空值被设置为只有前后缀
}
//设置空值,检查是否为null
public StringJoiner setEmptyValue(CharSequence emptyValue) {
this.emptyValue = Objects.requireNonNull(emptyValue,
"The empty value must not be null").toString();
return this;
}
@Override
public String toString() {
if (value == null) {
return emptyValue;//没有值将返回空值或者后续设置的空值
} else {
if (suffix.equals("")) {
return value.toString();//后缀为""直接返回字符串,不用添加
} else {
//后缀不为"",添加后缀,然后直接返回字符串,修改长度
int initialLength = value.length();
String result = value.append(suffix).toString();
// reset value to pre-append initialLength
value.setLength(initialLength);
return result;
}
}
}
初始化,先添加前缀,有了之后每次先添加间隔符,StringBuilder后续append字符串
public StringJoiner add(CharSequence newElement) {
prepareBuilder().append(newElement);
return this;
}
//合并StringJoiner,注意后面StringJoiner 的前缀就不要了,后面的appen进来
public StringJoiner merge(StringJoiner other) {
Objects.requireNonNull(other);
if (other.value != null) {
final int length = other.value.length();
// lock the length so that we can seize the data to be appended
// before initiate copying to avoid interference, especially when
// merge 'this'
StringBuilder builder = prepareBuilder();
builder.append(other.value, other.prefix.length(), length);
}
return this;
}
//初始化,先添加前缀,有了之后每次先添加间隔符
private StringBuilder prepareBuilder() {
if (value != null) {
value.append(delimiter);
} else {
value = new StringBuilder().append(prefix);
}
return value;
}
public int length() {
// Remember that we never actually append the suffix unless we return
// the full (present) value or some sub-string or length of it, so that
// we can add on more if we need to.
//不忘添加后缀的长度
return (value != null ? value.length() + suffix.length() :
emptyValue.length());
}
}
7.接口新增:默认方法与静态方法
8.最新的Date/Time API (JSR 310)
1、LocalDate/LocalTime/LocalDateTime
- LocalDate为日期处理类、LocalTime为时间处理类、LocalDateTime为日期时间处理类,方法都类似,具体可以看API文档或源码,选取几个代表性的方法做下介绍。
now相关的方法可以获取当前日期或时间,of方法可以创建对应的日期或时间,parse方法可以解析日期或时间,get方法可以获取日期或时间信息,with方法可以设置日期或时间信息,plus或minus方法可以增减日期或时间信息;
2 、TemporalAdjusters
这个类在日期调整时非常有用,比如得到当月的第一天、最后一天,当年的第一天、最后一天,下一周或前一周的某天等。
3、DateTimeFormatter
以前日期格式化一般用SimpleDateFormat类,但是不怎么好用,现在1.8引入了DateTimeFormatter类,默认定义了很多常量格式(ISO打头的),在使用的时候一般配合LocalDate/LocalTime/LocalDateTime使用,比如想把当前日期格式化成yyyy-MM-dd hh:mm:ss的形式:
// String -->LocalDateTime
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"); // 12小时
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); // 24小时
LocalDate localDate = LocalDate.parse("2019-12-07 07:43:53",formatter);
System.out.println(localDate);
System.out.println(localTime);
System.out.println(localDate);
9.新增base64加解密API
10.数组并行(parallel)操作
11.JVM的PermGen空间被移除:取代它的是Metaspace(JEP 122)
ALL
/*
JDK8新特性
*/
public class JDK8_features {
public List<Integer> list = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);
/**
* 1.Lambda表达式
*/
@Test
public void testLambda(){
list.forEach(System.out::println);
list.forEach(e -> System.out.println("方式二:"+e));
}
/**
* 2.Stream函数式操作流元素集合
*/
@Test
public void testStream(){
List<Integer> nums = Lists.newArrayList(1,1,null,2,3,4,null,5,6,7,8,9,10);
System.out.println("求和:"+nums
.stream()//转成Stream
.filter(team -> team!=null)//过滤
.distinct()//去重
.mapToInt(num->num*2)//map操作
.skip(2)//跳过前2个元素
.limit(4)//限制取前4个元素
.peek(System.out::println)//流式处理对象函数
.sum());//
}
/**
* 3.接口新增:默认方法与静态方法
* default 接口默认实现方法是为了让集合类默认实现这些函数式处理,而不用修改现有代码
* (List继承于Iterable<T>,接口默认方法不必须实现default forEach方法)
*/
@Test
public void testDefaultFunctionInterface(){
//可以直接使用接口名.静态方法来访问接口中的静态方法
JDK8Interface1.staticMethod();
//接口中的默认方法必须通过它的实现类来调用
new JDK8InterfaceImpl1().defaultMethod();
//多实现类,默认方法重名时必须复写
new JDK8InterfaceImpl2().defaultMethod();
}
public class JDK8InterfaceImpl1 implements JDK8Interface1 {
//实现接口后,因为默认方法不是抽象方法,重写/不重写都成!
// @Override
// public void defaultMethod(){
// System.out.println("接口中的默认方法");
// }
}
public class JDK8InterfaceImpl2 implements JDK8Interface1,JDK8Interface2 {
//实现接口后,默认方法名相同,必须复写默认方法
@Override
public void defaultMethod() {
//接口的
JDK8Interface1.super.defaultMethod();
System.out.println("实现类复写重名默认方法!!!!");
}
}
/**
* 4.方法引用,与Lambda表达式联合使用
*/
@Test
public void testMethodReference(){
//构造器引用。语法是Class::new,或者更一般的Class< T >::new,要求构造器方法是没有参数;
final Car car = Car.create( Car::new );
final List< Car > cars = Arrays.asList( car );
//静态方法引用。语法是Class::static_method,要求接受一个Class类型的参数;
cars.forEach( Car::collide );
//任意对象的方法引用。它的语法是Class::method。无参,所有元素调用;
cars.forEach( Car::repair );
//特定对象的方法引用,它的语法是instance::method。有参,在某个对象上调用方法,将列表元素作为参数传入;
final Car police = Car.create( Car::new );
cars.forEach( police::follow );
}
public static class Car {
public static Car create( final Supplier< Car > supplier ) {
return supplier.get();
}
public static void collide( final Car car ) {
System.out.println( "静态方法引用 " + car.toString() );
}
public void repair() {
System.out.println( "任意对象的方法引用 " + this.toString() );
}
public void follow( final Car car ) {
System.out.println( "特定对象的方法引用 " + car.toString() );
}
}
/**
* 5.引入重复注解
* 1.@Repeatable
* 2.可以不用以前的“注解容器”写法,直接写2次相同注解即可
*
* Java 8在编译器层做了优化,相同注解会以集合的方式保存,因此底层的原理并没有变化。
*/
@Test
public void RepeatingAnnotations(){
RepeatingAnnotations.main(null);
}
/**
* 6.类型注解
* 新增类型注解:ElementType.TYPE_USE 和ElementType.TYPE_PARAMETER(在Target上)
*
*/
@Test
public void ElementType(){
Annotations.main(null);
}
/**
* 7.最新的Date/Time API (JSR 310)
*/
@Test
public void DateTime(){
//1.Clock
final Clock clock = Clock.systemUTC();
System.out.println( clock.instant() );
System.out.println( clock.millis() );
//2. ISO-8601格式且无时区信息的日期部分
final LocalDate date = LocalDate.now();
final LocalDate dateFromClock = LocalDate.now( clock );
System.out.println( date );
System.out.println( dateFromClock );
// ISO-8601格式且无时区信息的时间部分
final LocalTime time = LocalTime.now();
final LocalTime timeFromClock = LocalTime.now( clock );
System.out.println( time );
System.out.println( timeFromClock );
// 3.ISO-8601格式无时区信息的日期与时间
final LocalDateTime datetime = LocalDateTime.now();
final LocalDateTime datetimeFromClock = LocalDateTime.now( clock );
System.out.println( datetime );
System.out.println( datetimeFromClock );
// 4.特定时区的日期/时间,
final ZonedDateTime zonedDatetime = ZonedDateTime.now();
final ZonedDateTime zonedDatetimeFromClock = ZonedDateTime.now( clock );
final ZonedDateTime zonedDatetimeFromZone = ZonedDateTime.now( ZoneId.of( "America/Los_Angeles" ) );
System.out.println( zonedDatetime );
System.out.println( zonedDatetimeFromClock );
System.out.println( zonedDatetimeFromZone );
//5.在秒与纳秒级别上的一段时间
final LocalDateTime from = LocalDateTime.of( 2018, Month.APRIL, 16, 0, 0, 0 );
final LocalDateTime to = LocalDateTime.of( 2019, Month.APRIL, 16, 23, 59, 59 );
final Duration duration = Duration.between( from, to );
System.out.println( "Duration in days: " + duration.toDays() );
System.out.println( "Duration in hours: " + duration.toHours() );
}
/**
* 8.新增base64加解密API
*/
@Test
public void testBase64(){
final String text = "就是要测试加解密!!abjdkhdkuasu!!@@@@";
String encoded = Base64.getEncoder()
.encodeToString( text.getBytes( StandardCharsets.UTF_8 ) );
System.out.println("加密后="+ encoded );
final String decoded = new String(
Base64.getDecoder().decode( encoded ),
StandardCharsets.UTF_8 );
System.out.println( "解密后="+decoded );
}
/**
* 9.数组并行(parallel)操作
*/
@Test
public void testParallel(){
long[] arrayOfLong = new long [ 20000 ];
//1.给数组随机赋值
Arrays.parallelSetAll( arrayOfLong,
index -> ThreadLocalRandom.current().nextInt( 1000000 ) );
//2.打印出前10个元素
Arrays.stream( arrayOfLong ).limit( 10 ).forEach(
i -> System.out.print( i + " " ) );
System.out.println();
//3.数组排序
Arrays.parallelSort( arrayOfLong );
//4.打印排序后的前10个元素
Arrays.stream( arrayOfLong ).limit( 10 ).forEach(
i -> System.out.print( i + " " ) );
System.out.println();
}
/**
* 10.JVM的PermGen空间被移除:取代它的是Metaspace(JEP 122)元空间
*/
@Test
public void testMetaspace(){
//-XX:MetaspaceSize初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整
//-XX:MaxMetaspaceSize最大空间,默认是没有限制
//-XX:MinMetaspaceFreeRatio在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
//-XX:MaxMetaspaceFreeRatio在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集
}
}
引用到的相关类:
public interface JDK8Interface1 {
//1.接口中可以定义静态方法了
public static void staticMethod(){
System.out.println("接口中的静态方法");
}
//2.使用default之后就可以定义普通方法的方法体了
public default void defaultMethod(){
System.out.println("接口中的默认方法");
}
}
public interface JDK8Interface2 {
//接口中可以定义静态方法了
public static void staticMethod(){
System.out.println("接口中的静态方法");
}
//使用default之后就可以定义普通方法的方法体了
public default void defaultMethod(){
System.out.println("接口中的默认方法");
}
}
/*
JDK8新特性
*/
public class RepeatingAnnotations {
@Target( ElementType.TYPE )
@Retention( RetentionPolicy.RUNTIME )
public @interface Filters {
Filter[] value();
}
@Target( ElementType.TYPE )
@Retention( RetentionPolicy.RUNTIME )
@Repeatable( Filters.class )
public @interface Filter {
String value();
String value2();
};
@Filter( value="filter1",value2="111" )
@Filter( value="filter2", value2="222")
//@Filters({@Filter( value="filter1",value2="111" ),@Filter( value="filter2", value2="222")}).注意:JDK8之前:1.没有@Repeatable2.采用本行“注解容器”写法
public interface Filterable {
}
public static void main(String[] args) {
//获取注解后遍历打印值
for( Filter filter: Filterable.class.getAnnotationsByType( Filter.class ) ) {
System.out.println( filter.value() +filter.value2());
}
}
}
/*
@Description:新增类型注解:ElementType.TYPE_USE 和ElementType.TYPE_PARAMETER(在Target上)
*/
public class Annotations {
@Retention( RetentionPolicy.RUNTIME )
@Target( { ElementType.TYPE_USE, ElementType.TYPE_PARAMETER } )
public @interface NonEmpty {
}
public static class Holder< @NonEmpty T > extends @NonEmpty Object {
public void method() throws @NonEmpty Exception {
}
}
public static void main(String[] args) {
final Holder< String > holder = new @NonEmpty Holder< String >();
@NonEmpty Collection< @NonEmpty String > strings = new ArrayList<>();
}
}