Java8的新特性
一、概述
- Java8 (又称JKD1.8)是Java语言开发的一个主要版本。
- Oracle公司于2014年3月18日发布Java8
- 支持Lambda表达式
- 函数式接口
- 新的Stream API
- 新的日期API
- 其他特性
二、Lambda
表达式
-
Lambda表达式:特殊的匿名内部类,语法更简洁
-
Lambda表达式允许把函数作为一个方法的参数(函数作为方法参数传递) ,将代码像数据一样传递
-
Lambda
表达式:在Java 8语言中引入的一种新的语法元素和操作符。这个操作符为->
, 该操作符被称为Lambda
操作符或箭头操作符。它将Lambda
分为两个部分:
- 左侧:指定了
Lambda
表达式需要的参数列表(其实就是接口中的抽象方法的形参列表); - 右侧:指定了
Lambda
体,是抽象方法的实现逻辑,也即Lambda
表达式要执行的功能(其实就是重写的抽象方法的方法体)。
- 语法格式1:无参,无返回值
Runable r = () -> {System.out.println("hello world");}
- 语法格式2:
Lambda
需要一个参数,但是没有返回值
Consumer<String> con = (String str) -> {System.out.println(str);}
- 语法格式3:数据类型可以省略,因为可由编译器推断得出,称为类型推断
Consumer<String> con = (str) -> {System.out.println(str);}
- 语法格式4:
Lambda
若只需要一个参数时,参数的小括号可以省略
Consumer<String> con = str -> {System.out.println(str);}
-
语法格式5:
Lambda
需要两个或以上的参数,多条执行语句,并且可以有返回值 -
注意事项:
- 形参列表的数据类型会自动推断
- 如果形参列表为空,只需保留()
- 如果形参只有1个,()可以省略,只需要参数的名称即可
- 如果执行语句只有一-句,且无返回值,{}可以省略,若有返回值,则若想省去{},则必须同时省略return,且执行语句也保证只有一句
- Lambda不会生成一个单独的内部类文件
//学生类
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Demo01 {
public static void main(String[] args) {
test03();
}
/*
* Lambda表达式的语法:
* ()->{}
* ()表示方法的参数、
* ->
* {}表示方法的实现
* */
//启动线程
public static void test01(){
//使用匿名内部类实现
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类启动线程");
}
}).start();
//使用Lambda表达式实现
new Thread(()-> System.out.println("使用lambda表达式启动线程...")).start();
}
public static void test02(){
//定义一个集合对集合进行排序
ArrayList<Student> students = new ArrayList<>();
students.add(new Student("aaa",15));
students.add(new Student("bbb",16));
students.add(new Student("ccc",17));
//使用匿名内部类实现
Collections.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.getAge()-o1.getAge();
}
});
//使用Lambda表达式实现
Collections.sort(students,((o1,o2)->o2.getAge()-o1.getAge()));
for (Student stu : students) {
System.out.println(stu);
}
}
public static void test03(){
//扫描D盘下的java文件
File file = new File("D:\\Folder");
//使用内名内部类进行扫描
/*
File[] files = file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().endsWith(".java");
}
});
*/
//使用Lambda表达式实现
File[] files1 = file.listFiles(pathname -> pathname.getName().endsWith(".java"));
for (File f : files1) {
System.out.println(f);
}
}
}
三、函数式接口
如果一个接口只有一个抽象方法,则该接口称之为函数式接口,函数式接口可以使用Lambda表达式,Lambda表达式会被匹配到这个抽象方法上
- @FunctionalInterface注解检测接口是否符合函数式接口
public class Demo01 {
public static void main(String[] args) {
//使用匿名内部类
test01(new MyFunctionalInterface() {
@Override
public void Show() {
System.out.println("匿名内部类实现");
}
});
//Lambda表达式实现
test01(()-> System.out.println("Lambda表达式实现"));
}
public static void test01(MyFunctionalInterface m1){
m1.Show();
}
@FunctionalInterface
interface MyFunctionalInterface{
void Show();
}
}
3.2java常用内置函数式接口
函数式接口 | 参数类型 | 返回值类型 | 用途 |
---|---|---|---|
Consumer<T> 消费型接口 | T | void | void accept(T t);对类型为T的对象应用操作 |
Supplier<T> 供给型接口 | 无 | T | T get(); 返回类型为T的对象 |
Function<T,R> 函数型接口 | T | R | R apply(T t);对类型为T的对象应用操作,并返回类型为R类型的对象。 |
Predicate<T> 断言型接口 | T | boolean | boolean test(T t);确定类型为T的对象是否满足条件,并返回boolean类型。 |
Consumer<T>
消费型接口
import java.util.function.Consumer;
public class Demo02 {
//Consumer<T>消费型接口
//定义一个方法传入一个字符串输出字符串长度
public static void test01(String str, Consumer<String> consumer){
consumer.accept(str);
}
public static void main(String[] args) {
//使用匿名内部类实现
test01("hello,java", new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s.length());
}
});
//使用Lambda表达式
test01("hello,java",t-> System.out.println(t.length()));
}
}
Supplier<T>
供给型接口
import java.util.function.Supplier;
public class Demo03 {
//定义一个方法 返回100以内最大的质数
public static int test01(Supplier<Integer> supplier){
return supplier.get();
}
public static void main(String[] args) {
// test01(new Supplier<Integer>() {
// @Override
// public Integer get() {
// for (int i = 100; i >=2 ; i--) {
// boolean flag=true;
// for (int j = 2; j <i ; j++) {
// if (i%j==0){
// flag=false;
// break;
// }
// }
// if (flag){
// return i;
// }
// }
// return 2;
// }
// });
//使用Lambda表达式
int num=test01(()->{
for (int i = 100; i >=2 ; i--) {
boolean flag=true;
for (int j = 2; j <i ; j++) {
if (i%j==0){
flag=false;
break;
}
}
if (flag){
return i;
}
}
return 2;
});
System.out.println(num);
}
}
Function<T,R>
函数型接口
import java.util.function.Function;
public class Demo04 {
//传入一个数组 返回指定的数组的和
public static int test01(int[] arr, Function<int[],Integer> function){
return function.apply(arr);
}
public static void main(String[] args) {
int[] arr={1,2,3,4,5};
// int sum=test01(arr, new Function<int[], Integer>() {
// @Override
// public Integer apply(int[] ints) {
// int sum=0;
// for (int i = 0; i <arr.length ; i++) {
// sum+=ints[i];
// }
// return sum;
// }
// });
//使用Lambda表达式
int sum=test01(arr,a->{
int sum1=0;
for (int i = 0; i <arr.length ; i++) {
sum1+=a[i];
}
return sum1;
});
System.out.println(sum);
}
}
Predicate<T>
断言型接口
import java.util.function.Predicate;
public class Demo05 {
//传入一个数 判断是否为3的倍数
public static boolean test01(int num, Predicate<Integer> predicate){
return predicate.test(num);
}
public static void main(String[] args) {
// boolean b=test01(15, new Predicate<Integer>() {
// @Override
// public boolean test(Integer integer) {
// return integer%3==0;
// }
// });
boolean b = test01(14, t -> t % 3 == 0);
System.out.println(b);
}
}
四、方法引用与构造器引用
4.1方法引用
- 方法引用是Lambda表达式的一种简写形式。如果Lambda表达式方法体中
- 只是调用一个特定的已经存在的方法,则可以使用方法引用。
- 常见形式
- 对象::实例方法
- 类::静态方法
- 类::实例方法
- 类::new
import java.util.Locale;
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
public class Demo01 {
public static void main(String[] args) {
/* test01("aaa", new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
*/
/* //使用Lambda表达式
test01("aaa",name-> System.out.println(name));
//使用方法引用
test01("bbb", System.out::println);//一个属性 一段逻辑代码
*/
/*
//传入一个字符串 变为大写返回这个字符串的大写
//使用Lambda表达式
test02("hello",s->s.toUpperCase());
//使用方法引用
test02("aaa",String::toUpperCase);
*/
test03(Math::random);
test04("aaa", Person::new);
}
public static void test01(String name, Consumer<String> consumer){
consumer.accept(name);
}
//传入一个字符串 变为大写返回这个字符串的大写
public static void test02(String str , Function<String,String> function){
System.out.println(function.apply(str));
}
//使用Random返回随机数
public static void test03(Supplier<Double> supplier){
System.out.println(supplier.get());
}
//传入name属性返回person对象
public static void test04(String name,Function<String,Person> function){
System.out.println(function.apply(name));
}
}
class Person{
String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
五、Stream API
5.1概述
-
流(Stream) 与集合类似,但集合中保存的是数据,而Stream中保存对集合或数组数据的操作
-
Stream自己不会存储元素
-
Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream
-
Stream操作是延迟执行的,会等到需要结果的时候才执行
5.2Stream
操作的三个步骤
- 创建
Stream
- 一个数据源(如:集合、数组),获取一个流
- 中间操作
- 产生一个中间操作链,对数据源的数据进行处理
- 终止操作(终端操作)
- 一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class Demo01 {
public static void main(String[] args) {
test03();
}
//如何创建Stream流对象
public static void test01(){
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
list.add("eee");
Stream<String> stream = list.stream();
/*
stream.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
*/
//使用Lambda表达式
stream.forEach(t-> System.out.println(t));
//通过方法引用
stream.forEach(System.out::println);
int[] arr = {1,2,3,4,5,6,7};
IntStream stream1 = Arrays.stream(arr);
stream1.forEach(System.out::println);
}
public static void test02(){
//流的中间操作
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
list.add("eee");
Stream<String> stream = list.stream();
//filter过滤集合元素长度大于4的
list.stream().filter(t->t.length( )>4).forEach(System. out::println);
//limit 限定查询前两个
list.stream().limit(2).forEach(System. out::println);
//skip跳过查询
list.stream().skip(2).forEach(System. out::println);
//分页查询
//第一页
list.stream().limit(2).forEach(System. out::println);
//第二页
list.stream().skip(2).limit(2).forEach(System. out::println);
//去重查询
list.stream().distinct().forEach(System. out::println);
//排序查询
list.stream().sorted(((o1, o2) -> o2.length()-o1.length())).forEach(System. out::println);
//map将元素进行重新映射
list.stream().map(li->"姓名为:"+li).forEach(System.out::println);
list.stream().forEach(li->System.out.println(Thread.currentThread().getName()+"---"+li));
list.stream().parallel().forEach(li->System.out.println(Thread.currentThread().getName()+"---"+li));
}
public static void test03() {
//流的终止操作
ArrayList<String> list = new ArrayList<>();
list.add("9");
list.add("5");
list.add("2");
list.add("7");
list.stream().forEach(System.out::println);
/*
//获取最大值
Optional<Integer> max = list.stream().map(Integer::parseInt).max((o1, o2) -> o1 - o2);
System.out.println(max.get());
//获取最小值
Optional<Integer> min = list.stream().map(Integer::parseInt).min((o1, o2) -> o1 - o2);
System.out.println(min.get());
*/
//获取个数
long count = list.stream().map(Integer::parseInt).filter(li -> li >=1).count();
System.out.println(count);
//reduce 计算
Optional<Integer> reduce = list.stream().map(Integer::parseInt).reduce((o1, o2) -> o1 + o2);
Optional<Integer> reduce1 = list.stream().map(Integer::parseInt).reduce(Integer::sum);
System.out.println(reduce1.get());
List<Integer> list1 = list.stream().map(Integer::parseInt).filter(li -> li > 5).collect(Collectors.toList());
list1.stream().forEach(System.out::println);
}
}
六、新时间API
- 之前时间API存在问题:线程安全问题、设计混乱
- 本地化日期时间APlI:
- LocalDate
- LocalTime
- LocalDateTime
- Instant: 时间戳
- Zoneld: 时区。
- Date、Instant、LocalDate Time的转换。
- DateTimeFormatter: 格式化类。
import javax.swing.text.DateFormatter;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class Demo {
public static void main(String[] args) {
test05();
}
//获取日期对象
public static void test01(){
LocalDate date = LocalDate.now();//当前系统日期
LocalTime time = LocalTime.now();//当前系统时间
LocalDateTime localDateTime = LocalDateTime.now();//系统时间+日期
System.out.println(date);
System.out.println(time);
System.out.println(localDateTime);
}
//获取日期对象的年 月 日 时 分 秒
public static void test02(){
LocalDateTime dateTime = LocalDateTime.now();
System.out.println(dateTime.getYear());
System.out.println(dateTime.getMonthValue());
System.out.println(dateTime.getDayOfMonth());
System.out.println(dateTime.getHour());
System.out.println(dateTime.getMinute());
System.out.println(dateTime.getSecond());
}
//设置日期对象的信息 年 月 日 时 分 秒
public static void test03(){
LocalDateTime dateTime = LocalDateTime.now();
dateTime = dateTime.withMonth(12).withDayOfMonth(25).withYear(2025);
System.out.println(dateTime.getYear());
System.out.println(dateTime.getMonthValue());
System.out.println(dateTime.getDayOfMonth());
}
//加减日期对象信息
public static void test04(){
LocalDateTime dateTime = LocalDateTime.now();
dateTime = dateTime.plusMonths(15).minusDays(2);
System.out.println(dateTime.getYear());
System.out.println(dateTime.getMonthValue());
System.out.println(dateTime.getDayOfMonth());
}
//
public static void test05(){
//将日期格式转换成字符串
// LocalDateTime dateTime = LocalDateTime.now();
//
// DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//
// String format = dateTimeFormatter.format(dateTime);
//
// System.out.println(format);
//
//将字符串解析成日期
String time="2022-12-25 10:10:10";
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime localDateTime = LocalDateTime.parse(time, dateTimeFormatter);
System.out.println(localDateTime);
}
}