前言
众所周知,JDK8作为常用的开发LTS(Long Term Support)版本,深受各大企业的爱好,但是里面的一些新特性,常被使用却直戳心胸,so,了解新特性早已是刻不容缓。
Lambda表达式
lambda表达式的要素
- 必须是接口
- 接口内必须只有一个抽象方法或者该接口可以被
@FunctionalInterface
注解修饰
1.创建一个接口
package com.ssy.demo;
public interface MyInter {
void action();
}
2.创建一个接口实现类
package com.ssy.demo;
public class MyInterImpl implements MyInter{
@Override
public void action() {
System.out.println("武术散打······不败神话");
}
}
3.测试demo
package com.ssy.demo;
public class JDK8 {
public static void main(String[] args) {
MyInterImpl myInter = new MyInterImpl();
myInter.action();
}
}
运行结果
Lambda的格式是
(类型 参数, 类型 参数,······)-> {
······
}
现在以上述的为例展示Lambda的表达式demo
package com.ssy.demo;
public class JDK8 {
public static void main(String[] args) {
MyInter inter = ()->{
System.out.println("Lambda表达式写出来的");
};
inter.action();
}
}
运行结果
注意:
- 如果接口的方法没有参数,那么Lambda表达式的小括号内没有数据
- 如果接口的方法有且仅有一个参数,那么小括号可以省略也可以不省略
- 如果只有方法体只有一条语句,可以不需要大括号
- 如果是有返回值的方法且方法体的语句仅有一条而且还是返回值,要么不写大括号不写return不写分号,要么写大括号写return写分号
说白了Lambda就是匿名函数,仅此而已。
package com.ssy.demo;
public class JDK8 {
public static void main(String[] args) {
Demo demo = name -> name + "真好吃";
String res = demo.eat("提拉米苏");
System.out.println(res);
}
}
interface Demo{
String eat(String name);
}
运行结果
函数式接口
供给型接口Supplier
特点:无参有返回值
源码
测试Demo
消费型接口Consumer
特点:有参无返回值
源码
测试Demo
Function<T, R>接口
特点:有参有返回值
源码
测试Demo
断言Predicate接口
特点:有参返回值为boolean类型
源码
测试Demo
接口强化
JDK8之前接口里面只有公有静态常量和公有抽象方法,JDK新增了默认方法和公共静态方法
package com.ssy.demo;
public class JDK8 {
public static void main(String[] args) {
Ssy.myWorld();
System.out.println("----------------------");
Demo demo = new Demo();
demo.action();
System.out.println("----------------------");
Ssy ssy = new Demo();
ssy.action();
}
}
interface Ssy{
default void action(){
System.out.println("动作事件");
}
static void myWorld(){
System.out.println("我的世界······");
}
}
class Demo implements Ssy{
@Override
public void action() {
System.out.println("按钮左键点击动作");
}
}
运行结果
默认方法与静态方法的区别
1.默认方法可以被继承,通过new对象调用
2.静态方法不能被继承,通过接口类名.方法名调用
方法引用
方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。
注意方法引用是一个Lambda表达式,其中方法引用的操作符是双冒号"::"
package com.ssy.demo;
import java.util.function.Consumer;
public class JDK8 {
public static void main(String[] args) {
Consumer<String> demo = System.out::println;
demo.accept("Hello Java");
}
}
运行结果
对象名引用成员方法
对象名::方法名
package com.ssy.demo;
public class JDK8 {
public static void main(String[] args) {
Demo demo = System.out::println;
demo.say("大家好,初来乍到,多多指教");
}
}
interface Demo{
void say(String text);
}
运行结果
类名引用静态方法
类名::静态方法
package com.ssy.demo;
public class JDK8 {
public static void main(String[] args) {
Demo<Boolean, String> demo = String::valueOf;
System.out.println(demo.out(false).length());
}
}
interface Demo<T,R>{
R out(T val);
}
运行结果
类名引用实例方法
类名::成员方法名
package com.ssy.demo;
public class JDK8 {
public static void main(String[] args) {
Demo<String, Boolean> demo = String::isEmpty;
System.out.println(demo.out("123"));
}
}
interface Demo<T,R>{
R out(T val);
}
运行结果
引用构造方法
类名::new
package com.ssy.demo;
public class JDK8 {
public static void main(String[] args) {
Demo<String,Bird> demo = Bird::new;
Bird bird = demo.out("我是一只小小鸟");
System.out.println(bird);
}
}
interface Demo<T,R>{
R out(T val);
}
class Bird{
private String name;
public Bird(String name){
this.name = name;
}
@Override
public String toString() {
return "Bird{ name: " + name + "}";
}
}
运行结果
Stream流
在使用集合相关的操作中,比如过滤、匹配、遍历、排序等操作时总是需要循环来遍历所有元素,从而来得到需要的结果,但我们更关注的是实现需求的逻辑,而不是如何循环。使用流操作更方便高效,流不是数据结构,只是在元数据集上定义了一组操作。
小demo1
package com.ssy.demo;
import java.util.ArrayList;
import java.util.List;
public class JDK8 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("250");
list.add("110");
list.add("100");
list.add("120");
list.add("99");
list.stream().filter(s -> Integer.parseInt(s)>120).forEach(System.out::println);
}
}
运行结果
小demo2
package com.ssy.demo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JDK8 {
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<>();
map.put("001",100);
map.put("002",99);
map.put("003",101);
map.put("004",98);
map.put("001",102);
map.values().stream().forEach(System.out::println);
}
}
运行结果
小demo3
package com.ssy.demo;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class JDK8 {
public static void main(String[] args) {
List<String> list = Stream.of("张三", "李四", "王五").collect(Collectors.toList());
long count = list.stream().count();
System.out.println(count);
}
}
运行结果
小demo4
package com.ssy.demo;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class JDK8 {
public static void main(String[] args) {
List<String> list = Stream.of("张三", "李四", "王五","赵六","孙七","周八","刘九","孙十").collect(Collectors.toList());
list.stream().limit(2).forEach(System.out::println);
}
}
运行结果
小demo5
package com.ssy.demo;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class JDK8 {
public static void main(String[] args) {
List<String> list = Stream.of("张三", "李四", "王五","赵六","孙七","周八","刘九","孙十").collect(Collectors.toList());
list.stream().skip(7).forEach(System.out::println);
}
}
运行结果
小demo6
package com.ssy.demo;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class JDK8 {
public static void main(String[] args) {
List<String> list = Stream.of("1", "2", "3","4","5","6","7","8").collect(Collectors.toList());
list.stream().map(s->Integer.parseInt(s)>5).forEach(System.out::println);
}
}
运行结果
小demo7
package com.ssy.demo;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class JDK8 {
public static void main(String[] args) {
List<String> list = Stream.of("1111","2","33","444").collect(Collectors.toList());
list.stream().sorted((a,b)->a.length()-b.length()).forEach(System.out::println);
}
}
运行结果
小demo8
package com.ssy.demo;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class JDK8 {
public static void main(String[] args) {
List<String> list = Stream.of("111","2","2","111").collect(Collectors.toList());
list.stream().distinct().forEach(System.out::println);
}
}
运行结果
小demo9
package com.ssy.demo;
import java.util.ArrayList;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class JDK8 {
public static void main(String[] args) {
ArrayList<Integer> arr = Stream.of(1, 2, 3, 4, 5, 6).collect(Collectors.toCollection(ArrayList::new));
arr.stream().forEach(System.out::println);
}
}
运行结果
stream链式调用的时候注意终结点
时间和日期
JDK8之前用的是线程不安全的Calendar.getInstance对日期进行操作,JDK8推出了新的时间日期的API,且线程是安全的。
日期
package com.ssy.demo;
import java.time.LocalDate;
public class JDK8 {
public static void main(String[] args) {
LocalDate date = LocalDate.now();
System.out.println("当前的日期是" + date);
System.out.println("年:" + date.getYear());
System.out.println("英文月:" + date.getMonth().toString().toLowerCase());
System.out.println("月份值:" + date.getMonthValue());
System.out.println("日:" + date.getDayOfMonth());
LocalDate year = date.withYear(2000);
System.out.println("修改之后的日期:" + year);
}
}
运行结果
时间
package com.ssy.demo;
import java.time.LocalTime;
public class JDK8 {
public static void main(String[] args) {
LocalTime now = LocalTime.now();
System.out.println(now);
System.out.println(now.getHour());
System.out.println(now.withHour(12));
}
}
运行结果
日期时间
package com.ssy.demo;
import java.time.LocalDateTime;
public class JDK8 {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
System.out.println(now);
System.out.println(now.getYear());
System.out.println(now.withMonth(2));
}
}
运行结果
格式化
package com.ssy.demo;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class JDK8 {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String s = now.format(formatter);
System.out.println(s);
}
}
运行结果
日期时间差
package com.ssy.demo;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
public class JDK8 {
public static void main(String[] args) {
LocalDate date = LocalDate.now();
LocalDate dateEnd = LocalDate.of(2030, 10, 10);
Period dpe = Period.between(date, dateEnd);
System.out.println(dpe.getYears());
LocalTime time = LocalTime.now();
LocalTime timeEnd = LocalTime.of(22, 22, 22);
Duration tdu = Duration.between(time, timeEnd);
System.out.println(tdu.toHours());
}
}
运行结果
时间校正器
package com.ssy.demo;
import java.time.*;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
public class JDK8 {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
TemporalAdjuster t = temporal -> {
LocalDateTime dateTime = (LocalDateTime) temporal;
return dateTime.plusMonths(1).withDayOfMonth(1);
};
System.out.println(now.with(t));
System.out.println(now.with(TemporalAdjusters.firstDayOfNextYear()));
}
}
运行结果
重复注解和类型注解
重复注解
JDK5出现了注解,但是不能在一个类、方法、字段上出现重复的注解,JDK8很好的解决了这个问题。
前提:需要一个注解容器和一个注解内容,注解内容上的@Repeatable用来指定重复注解的容器,getAnnotationByType获取定义的所有的重复的注解。
package com.ssy.demo;
import java.lang.annotation.*;
public class JDK8 {
public static void main(String[] args) {
Demo[] demos = Test.class.getAnnotationsByType(Demo.class);
for (Demo demo : demos) {
System.out.println(demo.value());
}
}
}
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno{
Demo[] value() default {};
}
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(MyAnno.class)
@interface Demo{
String value() default "";
}
@Demo("张三")
@Demo("李浩")
class Test{
}
运行结果
类型注解
JDK8在@Target中新出现了TYPE_USE(表示注解可以写在任何用到类型的地方)、TYPE_PARAMETER(表示该注解能写在类型参数的声明语句中,也就是泛型)两个枚举变量