Java8新特性
Java8(又称JDK1.8)是Java语言开发的一个主要版本
Oracle公司于2014年3月18日发布Java8
一、Lambda表达式
1.1 概念
-
特殊的匿名内部类,语法更简洁
-
Lambda表达式允许把函数作为一个方法的参数(函数作为方法参数传递),将代码想数据一样传递
语法
- 操作符:->
- ->(箭头操作符)将表达式分成两部分
- 左侧:(参数1,参数2…)表示参数列表
- 右侧:{}内部式方法体
<函数式接口><变量名> = (参数1,参数2...)->{
//方法体
};
注意事项
- 形参列表的数据类型会自动推断
- 如果形参列表为空,只需保留()
- 如果形参只有1个,()可以省略,只需要参数的名称即可。
- 如果执行语句只有一句,且无返回值,{}可以省略,若有返回值,则想省去{},则必须同时省略return,且执行语句也保证只有一句
- Lambda不会生成一个单独的内部类文件
1.2 案例
Lambda转化过程
//1匿名内部类:创建Runnable对象
Runnable runnable=new Runnable() {
@Override
public void run() {
System.out.println("子线程开始执行了...");
}
};
new Thread(runnable).start();
//2使用Lambda表达式优化
Runnable runnable2= ()->System.out.println("子线程开始执行了...");
new Thread(runnable2).start();
//Comparator
Comparator<Integer> comparator=new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
//使用Lambda表达式优化
Comparator<Integer> comparator2= (o1, o2)->Integer.compare(o1, o2);
TreeSet<Integer> treeSet=new TreeSet<>(comparator2);
二、函数式接口
2.1 概念
- 如果一个接口只有一个抽象方法,则该接口称之为函数式接口,函数式接口可以使用Lambda表达式,Lambda表达式会被匹配到这个抽象方法上
- @FunctionalInterface 注解检测接口是否符合函数式接口
2.2 常见函数式接口
示例代码
- Consumer 消费型接口
//省略了主函数
//匿名内部类形式
System.out.println("------Consumer消费型-----");
happpy(122, new Consumer<Double>() {
@Override
public void accept(Double aDouble) {
System.out.println(aDouble);
}
});
//Lambda表达式形式
happpy(1000,money ->System.out.println("聚餐,花费:"+money));
//Consumer:消费型接口 有参无返回值
public static void happpy(double money, Consumer<Double> con){
con.accept(money);
}
- Supplier 供给型接口
System.out.println("------Supplier供给型-----");
int[] arr=getNums(3,() ->new Random().nextInt(900)+100);
for (int i : arr) {
System.out.println(i);
}
//Supplier:供给型接口 无参有返回值
public static int[] getNums(int count, Supplier<Integer> sup){
int[] nums=new int[count];
for(int i=0;i<count;i++){
nums[i]=sup.get();
}
return nums;
}
- Function<T,R> 函数型接口
System.out.println("------Function函数型-----");
String r=handler("hello",s-> s.toUpperCase());
System.out.println(r);
//Function:函数型接口,有参有返回值
public static String handler(String str, Function<String,String> fun){
return fun.apply(str);
}
- Predicate 断言型接口
System.out.println("------Predicate断言型-----");
List<String> names=new ArrayList<>();
names.add("zhangsan");
names.add("lisi");
names.add("zhangsanfeng");
names.add("zhangwuji");
names.add("cancan");
List<String> names2=filter(names,s-> s.startsWith("li"));
for (String s : names2) {
System.out.println(s);
}
//Predicate:断言型接口,有参有返回值 返回值boolean类型
public static List<String> filter(List<String> names, Predicate<String> p){
List<String> list=new ArrayList<>();
for (String name : names) {
if(p.test(name)){
list.add(name);
}
}
return list;
}
三、方法引用
3.1 概念
方法引用是Lambda表达式的一种简写形式。如果Lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法的引用
3.2 常见形式
3.2.1 第一种形式
- 对象::实例方法
- Lambda表达式方法体中只是调用一个特定的已经存在的方法
- 方法的参数,返回值和接口中的方法参数一致
示例代码
//Consumer<T> : void accept(T t) 有参数,无返回
//println():有参,无返回
Consumer<String> consumer= s -> System.out.println(s);
Consumer<String> consumer2= System.out::println;
consumer2.accept("hello");
consumer2.accept("你好");
3.2.2 第二种形式
- 类::静态方法
- Lambda表达式方法体中只是调用一个特定的已经存在的方法
- 方法的参数,返回值和接口中的方法的参数一致
Comparator<Integer> comparator=(o1,o2)->Integer.compare(o1,o2);
Comparator<Integer> comparator2=Integer::compare;
//源码分析
Comparator<T> //有两个参数,并且有返回值
int compare(T o1, T o2);
Integer//静态方法,有两个参数,有返回值
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
3.2.3 第三种形式
- 类::实例方法
- Lambda表达式方法体中只是调用一个特定的已经存在的方法
- 有一个参数作为方法的调用者,其他的参数,返回值和接口中的方法一致
Comparator<String> comparator3=(o1,o2)->o1.compareTo(o2);
Comparator<String> comparator4=String::compareTo;
3.2.4 第四种形式
- 类::new
- Lambda表达式方法体中只是调用构造方法创建对象
- 构造方法参数和接口中方法参数一致
Supplier<Employee> sup=()->new Employee();
Supplier<Employee> sup2=Employee::new;
System.out.println(sup2.get());
MySupplier<Employee> sup3=Employee::new;
Employee e = sup3.get("张三", 20, 20000);
System.out.println(e.toString());
interface Suplier<T>{//无参,有返回值
T get();
}
public Employ(){//无参,需创建对象
}
----------------------------------
interface MyInterface<T>{//有参,有返回值
T demo(String name,int age)
}
public Empoyee(String name,int age){//有参,创建对象
this.name = name;
this.age = age;
}
3.2.5 第五种形式
- 元素类型[]::new
- Lambda表达式方法体中创建数组
- 参数作为数组的长度
Function<Integer,String[]> function=n->new String[n];
Function<Integer,String[]> function2=String[]::new;
String[] arr = function2.apply(5);
System.out.println(arr.length);
interface Funtion<T,R>{
R apply(T t);
}
四、Stream
4.1 概念
流(Stream)与集合类似,但集合中保存的是数据,而Stream中保存对集合或数组数据的操作
特点
- Stream自己不会存储元素
- Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream
- Stream操作是延迟执行的,会等到需要结果的时候才执行
4.2 Stream使用步骤
4.2.1 创建流
- 通过Collection集合的stream()或parallelStream()方法
- 通过Arrays类的stream()方法
- 通过Stream接口的of(),iterate(),generate()方法
- 通过IntStream,LongStream,DoubleStream接口中的of,range,rangeClosed方法
示例代码
//创建流
//(1)通过Collection集合的stream()或parallelStream()方法。
ArrayList<String> arrayList=new ArrayList<>();
arrayList.add("beijing");
arrayList.add("shanghai");
arrayList.add("hangzhou");
arrayList.add("guangzhou");
arrayList.add("dongguan");
Stream<String> stream = arrayList.stream();
stream.filter(s->s.length()>=8)
.forEach(s-> System.out.println(s));
//(2)通过Arrays类的stream()方法。
IntStream stream1 = Arrays.stream(new int[]{10, 20, 30, 40, 50});
stream1.forEach(n-> System.out.println(n));
//(3)Stream的方法:of() 指定元素 iterate()无限迭代流 generate()无限生成流
Stream<String> stringStream = Stream.of(new String[]{"苹果", "橘子", "葡萄"});
stringStream.forEach(s-> System.out.println(s));
Stream<Integer> iterate = Stream.iterate(1, n -> n * 2);
iterate.limit(5).forEach(s-> System.out.println(s));
Stream<Integer> generate = Stream.generate(() -> new Random().nextInt(100));
generate.limit(5).forEach(s-> System.out.println(s));
//(4)使用IntStream LongStream DoubleStream of() 指定元素 range()产生指定范围的数字 不包含结束 rangeClosed() 产生指定范围的数字 包含结束
IntStream intStream = IntStream.of(100, 200, 300);
intStream.forEach(s-> System.out.println(s));
IntStream.rangeClosed(0, 100).forEach(s-> System.out.println(s));
4.2.2 中间操作
- filter,limit,skip,distinct,sorted
- map
- parallel
//中间操作:
//filter、limit、skip、distinct、sorted
//map
//parallel
//(1)filter、limit、skip、distinct、sorted
List<Employee> list = new ArrayList<>();
Employee e1 = new Employee("灿灿", 18, 28000);
Employee e2 = new Employee("龙哥", 16, 25000);
Employee e3 = new Employee("华哥", 28, 50000);
Employee e4 = new Employee("赵吉", 20, 35000);
Employee e5 = new Employee("子旭", 19, 30000);
Employee e6 = new Employee("子旭", 19, 30000);
list.add(e1);
list.add(e2);
list.add(e3);
list.add(e4);
list.add(e5);
list.add(e6);
//filter 过滤
System.out.println("-----filter------");
list.stream()
.filter(e->e.getAge()>=20)
.forEach(System.out::println);
//limit 限制
System.out.println("-----limit------");
list.stream()
.limit(2)
.forEach(System.out::println);
//skip 跳过
System.out.println("------skip-----");
list.stream()
.skip(2)
.limit(2)
.forEach(System.out::println);
//distinct 去掉重复 (重复依据 hashcode和equals)
System.out.println("----distinct 去掉重复-----");
list.stream()
.distinct()
.forEach(System.out::println);
//sorted 排序(实现Comparable接口,重写compareTo方法/创建比较器)
System.out.println("-----sorted() 排序------");
list.stream()
.sorted()
.forEach(System.out::println);
//map 映射
//打印所有员工的姓名
System.out.println("------map-------");
list.stream()
.map(e->e.getSalary())
.forEach(System.out::println);
//parallel 并行流
System.out.println("-----并行流-----");
// list.stream()
// .parallel()
// .forEach(System.out::println);
list.parallelStream()
.forEach(System.out::println);
public class Employee implements Comparable<Employee> {
private String name;
private int age;
private double salary;
public Employee(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
System.out.println("带参构造方法");
}
public Employee() {
System.out.println("默认构造方法");
}
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;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age &&
Double.compare(employee.salary, salary) == 0 &&
Objects.equals(name, employee.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, salary);
}
@Override
public int compareTo(Employee o) {
int n1=this.getAge()-o.getAge();
int n2=Double.compare(this.getSalary(), o.getSalary());
return n1==0?n2:n1;
}
}
4.2.3 终止操作
- forEach,min,max,count
- reduce,collect
//终止操作
//forEach、min、max、count
//reduce、collect
List<Employee> list = new ArrayList<>();
Employee e1 = new Employee("灿灿", 18, 28000);
Employee e2 = new Employee("龙哥", 16, 25000);
Employee e3 = new Employee("华哥", 28, 50000);
Employee e4 = new Employee("赵吉", 20, 35000);
Employee e5 = new Employee("子旭", 19, 30000);
Employee e6 = new Employee("子旭", 19, 30000);
list.add(e1);
list.add(e2);
list.add(e3);
list.add(e4);
list.add(e5);
list.add(e6);
//forEach 遍历 min 最小元素 max最大元素 count元素个数
//查找工资最低的员工
//Optional:防止空指针异常,返回的数据封装Optional对象。
Optional<Employee> min = list.stream()
.min((o1, o2) -> Double.compare(o1.getSalary(), o2.getSalary()));
System.out.println(min.get().toString());
Optional<Employee> max= list.stream()
.max((o1, o2) -> Double.compare(o1.getSalary(), o2.getSalary()));
System.out.println(max.get().toString());
long count = list.stream().count();
System.out.println("元素个数:"+count);
//reduce:归约,统计
//统计所有人的工资和
Optional<Double> sum = list.stream()
.map(e -> e.getSalary())
.reduce((s1, s2) -> s1 + s2);
System.out.println("所有工资和:"+sum.get());
System.out.println("平均工资:"+sum.get()/count);
//collect:收集
//获取所有人的姓名转成list集合
List<String> names = list.stream()
.map(e -> e.getName())
.collect(Collectors.toList());
for (String name : names) {
System.out.println(name);
}
//延迟操作 :添加所有的中间操作都不会立即执行。
System.out.println("--------延迟操作 ------------");
long c= list.stream()
.filter(e->{
System.out.println("执行过了"+e.toString());
return e.getAge()>=20;
}).count();
System.out.println(c);
五、时间
5.1 本地化日期API
- LocalDate
- LocalTime
- LocalDateTime : 类似于Calendar
public class LocalDateTimeDemo {
public static void main(String[] args) {
//本地日期时间类
LocalDateTime localDateTime=LocalDateTime.now();
System.out.println(localDateTime.toString());
//昨天
LocalDateTime yesterday = localDateTime.minusDays(1);
System.out.println(yesterday);
//明天
LocalDateTime tomorrow = localDateTime.plusDays(1);
System.out.println(tomorrow);
//指定日期和时间的对象
LocalDateTime date = LocalDateTime.of(1997, 7, 1, 10, 10, 15);
System.out.println(date.toString());
//获取日期和时间信息
System.out.println(localDateTime.getYear());
System.out.println(localDateTime.getMonthValue());
System.out.println(localDateTime.getDayOfMonth());
System.out.println(localDateTime.getHour());
System.out.println(localDateTime.getMinute());
System.out.println(localDateTime.getSecond());
System.out.println("---------不可变---------");
//设置日期和时间(不可变)
LocalDateTime localDateTime1 = localDateTime.withMonth(2);
System.out.println(localDateTime);
System.out.println(localDateTime1);
Date d=new Date();//(可变)
d.setTime(System.currentTimeMillis()-60*60*24*1000);
System.out.println(d);
}
}
5.2 Instant 时间戳
类似于Date
public class InstantDemo {
public static void main(String[] args) throws InterruptedException {
//创建Instant
Instant instant=Instant.now();
System.out.println(instant);
System.out.println("秒:"+instant.getEpochSecond());
System.out.println("毫秒:"+instant.toEpochMilli());
//昨天
Instant yesterday=instant.minusMillis(60*60*24*1000);
System.out.println(yesterday);
//明天
Instant tomorrow=instant.plusMillis(60*60*24*1000);
System.out.println(tomorrow);
//计时
Instant start=Instant.now();
Thread.sleep(3000);
Instant end=Instant.now();
long t = Duration.between(start, end).toMillis();
System.out.println("用时:"+t);
}
}
5.3 时区
public class ZoneIdDemo {
public static void main(String[] args) {
//ZoneId时区类
Set<String> set = ZoneId.getAvailableZoneIds();
for (String s : set) {
System.out.println(s);
}
//获取默认时区
System.out.println("--------默认时区-------");
System.out.println(ZoneId.systemDefault());
}
}
5.4 案例
public class InstantDemo2 {
public static void main(String[] args) {
//演示转换
//(1)LocalDateTime-->Instant-->Date
System.out.println("---------LocalDateTime-->Instant-->Date-------");
LocalDateTime now=LocalDateTime.now();
Instant instant = now.atZone(ZoneId.systemDefault()).toInstant();
Date from = Date.from(instant);
System.out.println(from);
//(2)Date-->Instant-->LocalDateTime
System.out.println("---------Date-->Instant-->LocalDateTime-------");
Instant instant1 = from.toInstant();
LocalDateTime localDateTime = instant1.atZone(ZoneId.systemDefault()).toLocalDateTime();
System.out.println(localDateTime);
}
}
5.5 格式化类
DateTimeFormatter
public class DateTimeFormaterDemo {
public static void main(String[] args) {
//时间格式化类DateTimeFormatter
DateTimeFormatter dtf= DateTimeFormatter.ofPattern("yyyy/M.dd HH:mm:ss");
//(1) 日期---》字符串
LocalDateTime localDateTime=LocalDateTime.now();
String format = dtf.format(localDateTime);
System.out.println(format);
//(2)字符串--->日期
LocalDateTime parse = LocalDateTime.parse("1998/10.10 10:20:30",dtf);
System.out.println(parse);
}
}