java8 新特性
1.java8概述
Java8 (又称JKD1.8) 是Java 语言开发的一个主要版本。
Oracle公司于2014年3月18日发布Java8 。
2.Lambda表达式
Lambda表达式:特殊的匿名内部类,语法更简洁。
Lambda表达式允许把函数作为一个方法的参数(函数作为方法参数传递),将代码像数据一样传递。
基本语法:
<函数式接口> <变量名> = (参数1,参数2...) -> {
//方法体
};
Lambda引入了新的操作符:->(箭头操作符),->将表达式分成两部分
- 左侧:(参数1,参数2…)表示参数列表
- 右侧:{}内部是方法体
注意事项:
- 形参列表的数据类型会自动推断。
- 如果形参列表为空,只需保留() 。
- 如果形参只有1个,()可以省略,只需要参数的名称即可。
- 如果执行语句只有一句,且无返回值,{}可以省略,若有返回值,则若想省去{},则必须同时省略return,且执行语句也保证只有一句。
- Lambda不会生成一个单独的内部类文件。
测试代码1
public class Demo1 {
public static void main(String[] args) {
//创建Runnable对象
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("asd");
}
}).start();
//优化后
new Thread(() -> System.out.println("asd")).start();
//创建Comparator
new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
//优化后
Comparator<Integer> comparator = (o1, o2) -> Integer.compare(o1, o2);
}
}
测试代码2
class Employee{
private int age;
private int money;
public Employee() {
}
public Employee(int age, int money) {
this.age = age;
this.money = money;
}
//setter , getter
@Override
public String toString() {
}
}
interface MyInterface<T> {
boolean test(T t);
}
public class Demo2 {
public static void main(String[] args) {
ArrayList<Employee> employees = new ArrayList<>();
employees.add(new Employee(20, 200));
employees.add(new Employee(25, 400));
employees.add(new Employee(30, 600));
//内涵方法的回调
List<Employee> filter = filter(employees, e -> e.getMoney() > 300);
for (Employee o : filter) {
System.out.println(o.toString());
}
}
public static List<Employee> filter(List<Employee> list, MyInterface<Employee> e) {
ArrayList<Employee> employees = new ArrayList<>();
for (Employee employee : list) {
if (e.test(employee)) {
employees.add(employee);
}
}
return employees;
}
}
[wppay]
3.函数式接口
如果一个接口只有一个抽象方法,则该接口称之为函数式接口,函数式接口可以使用Lambda表达式,Lambda表达式会被匹配到这个抽象方法上。
@FunctionalInterface 注解检测接口是否符合函数式接口。
常见函数式接口
//演示四个函数式接口
public class FunctionalDemo {
public static void main(String[] args) {
//1.
happy(2000, new Consumer<Double>() {
@Override
public void accept(Double aDouble) {
System.out.println(aDouble);
}
});
happy(1000, money -> System.out.println(money));
//2.
int[] nums = getNums(3, () -> new Random().nextInt(900) + 100);
for (int num : nums) {
System.out.print(num + " ");
}
//3.
String hello = handler("hello", s -> s.toUpperCase());
System.out.println(hello);
//4.
List<String> list = new ArrayList<>();
list.add("liuzhiu");
list.add("asdliu");
list.add("liuasd");
/* List<String> strings = filter2(list, new Predicate<String>() {
@Override
public boolean test(String s) {
if (s.startsWith("liu")) {
return true;
}
return false;
}
});*/
//优化后
List<String> strings = filter2(list, s -> s.startsWith("liu"));
for (String string : strings) {
System.out.print(string + " ");
}
}
//Consumer 消费型接口 有参无返回值
public static void happy(double money, Consumer<Double> con) {
con.accept(money);
}
//Supplier : 供给型 无参有返回值
public static int[] getNums(int count, Supplier<Integer> sup) {
int[] ints = new int[count];
for (int i = 0; i < count; i++) {
ints[i] = sup.get();
}
return ints;
}
//Function : 函数型接口 有参有返回值
public static String handler(String str, Function<String, String> f) {
return f.apply(str);
}
//Predicate : 断言型 判断
public static List<String> filter2(List<String> list, Predicate<String> p) {
ArrayList<String> list1 = new ArrayList<String>();
for (String s : list) {
if (p.test(s)) {
list1.add(s);
}
}
return list1;
}
}
4.方法引用
方法引用是Lambda表达式的一种简写形式。如果Lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用。
常见形式
- 对象::实例方法
- 类::静态方法
- 类::实例方法
- 类::new
- 元素类型[]::new
public class MethodRef {
public static void main(String[] args) {
//了解
//方法引用是Lambda表达式的一种简写形式。
//如果Lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用。
///第一种形式,对象::实例方法
//(1)Lambda表达式方法体中只是调用一个特定的已经存在的方法。
//(2)方法的参数和返回值和接口中的方法一致。
Consumer<String> consumer = s -> System.out.println(s);
Consumer<String> consumer2 = System.out::println;
consumer2.accept("hello");
consumer2.accept("你好");
//第二种形式,类::静态方法
//(1).Lambda表达式方法体中只是调用一个特定的已经存在的方法。
//(2)方法的参数和返回值和接口中的方法一致。
Comparator<Integer> comparator = (o1, o2) -> Integer.compare(o1, o2);
Comparator<Integer> comparator2 = Integer::compare;
//第三种:类::实例方法
//(1).Lambda表达式方法体中只是调用一个特定的已经存在的方法。
//(2) 有一个参数作为方法调用者,其他的和接口的方法一致
Comparator<String> comparator3 = (o1, o2) -> o1.compareTo(o2);
Comparator<String> comparator4 = String::compareTo;
//第四章形式:类::new
//调用的无参构造方法创建对象
//构造方法参数和接口类型一致
Supplier<Employee> sup = () -> new Employee();
Supplier<Employee> sup2 = Employee::new;
System.out.println(sup2.get());
//第五种形式:元素类型[]::new
//创建一个数组
//方法的参数作为数组的个数
Function<Integer, String[]> function = s -> new String[s];
Function<Integer, String[]> function2 = String[]::new;
String[] apply = function2.apply(5);
}
}
5.* StreamAPI
什么是Stream
流(Stream)与集合类似,但集合中保存的是数据,而Stream中保存对集合或数组数据的操作。
Stream特点
- Stream 自己不会存储元素。
- Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
-
Stream 操作是延迟执行的,会等到需要结果的时候才执行。
即执行终止操作。
Stream使用步骤
- 创建:
- 新建一个流。
- 中间操作:
- 在一个或多个步骤中,将初始Stream转化到另一个Stream的中间操作。
- 终止操作:
- 使用一个终止操作来产生一个结果。该操作会强制之前的延迟操作立即执行,在此之后,该Stream就不能使用了。
创建Stream
通过Collection集合的stream()或parallelStream()方法。
通过Arrays类的stream()方法。
- 通过Stream接口的of()、iterate()、generate()方法。
- 通过IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法。
//1.创建一个流(四种方法)
public class StreamDemo1 {
public static void main(String[] args) {
//(1).* 对集合:通过Collection集合的stream()或parallelStream()方法
ArrayList<String> list = new ArrayList<>();
list.add("aad");
list.add("ba");
list.add("casddd");
list.add("dddd");
Stream<String> stream = list.stream();
stream.filter(s -> s.length() >= 5).forEach(s -> System.out.println(s));
//(2)* 对数组:Arrays.stream
IntStream intStream = Arrays.stream(new int[] {12, 23, 34, 12, 23});
intStream.forEach(n -> System.out.print(n + " "));
//(3)Stream的方法 of,iterate()迭代流,generate() 生成流
Stream<String> stringStream = Stream.of(new String[] {"a", "b", "c"});
Stream.iterate(0, n -> n + 2).limit(5).forEach(System.out::println);//以0为基础,每次加2
System.out.println("---------");
Stream.generate(() -> new Random().nextInt(100))
.limit(5)
.forEach(System.out::println);
//(4)使用IntStream,LongStream,DoubleStream
//of range() 左闭右开 rangeClose() 左闭右闭
IntStream.of(100, 200, 300).forEach(System.out::println);
//生产0-99的数字
IntStream.range(0, 100).forEach(System.out::println);
IntStream.rangeClosed(0, 100).forEach(System.out::println);
}
}
中间操作
- 中间操作:
- filter、limit、skip、distinct、sorted
- map
- parallel
//添加中间操作 filter limit skip distinct sorted
class StreamDemo2 {
public static void main(String[] args) {
ArrayList<Employee> e = new ArrayList<>();
e.add(new Employee("20", 800));
e.add(new Employee("25", 300));
e.add(new Employee("30", 600));
e.add(new Employee("30", 600));
e.stream().filter(s -> s.getMonth() >= 300).forEach(System.out::println);
System.out.println("---------------");
e.stream().limit(2).forEach(System.out::println);
System.out.println("---------------");
e.stream().skip(2).limit(2).forEach(System.out::println);
System.out.println("---------------");
//distinct 需要重写hashCode()和equals()
e.stream().distinct().forEach(System.out::println);
System.out.println("---------------");
//sorted
e.stream().sorted(new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
return o1.getMonth() - o2.getMonth();
}
}).forEach(System.out::println);
System.out.println("---------------");
//map映射 没有产生集合 案例:打印所有员工的姓名
e.stream().map(list -> list.getName()).forEach(System.out::println);
System.out.println("---------------");
//parallel 并行流(多线程)
e.stream().parallel().forEach(System.out::println);
//e.parallelStream().forEach(System.out::println);
}
}
验证并行流 串行流 , UUID 随机生成ID
public class StreamDemo3 {
public static void main(String[] args) {
List<String> list=new ArrayList<>();
for (int i = 0; i < 999999; i++) {
list.add(UUID.randomUUID().toString());
}
// 2100 2900 1831
long start=System.currentTimeMillis();
//串行流 (单线程)2100 2900 1831
//并行流(多线程) 1618 2350 1313
long count=list.parallelStream()
.sorted()
.count();
System.out.println("元素个数:"+count);
long end=System.currentTimeMillis();
System.out.println("用时:"+(end-start));
}
}
终止操作
- 终止操作:
- forEach、min、max、count
- reduce、collect
//终止操作
//forEach 遍历 min 最小值 max 最大值 count 元素个数
//reduce 归约:统计 collect 收集
class StreamDemo4 {
public static void main(String[] args) {
ArrayList<Employee> e = new ArrayList<>();
e.add(new Employee("20", 800));
e.add(new Employee("25", 300));
e.add(new Employee("30", 600));
e.add(new Employee("30", 600));
//查找月份最低的
//Optional 防止空指针异常,返回的数据封装Optional对象
Optional<Employee> min = e.stream().min(new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
return Integer.compare(o1.getMonth(), o2.getMonth());
}
});
System.out.println(min.get().getMonth());
//count 元素个数
System.out.println(e.stream().count());
//reduce 归约:统计
//统计所有人的工资的和 二元运算符
Optional<Integer> sum = e.stream()
.map(s -> s.getMonth())
.reduce((s1, s2) -> s1 + s2);
System.out.println(sum.get());
System.out.println("--------------");
//collect : 收集
//获取所有人的姓名
List<String> collect = e.stream()
.map(s -> s.getName())
.collect(Collectors.toList());
for (String s : collect) {
System.out.println(s);
}
//延迟操作,添加所有的中间操作都不会立即执行,直到有终止操作才会执行
}
}
6.新的时间API
- 之前时间API存在问题:线程安全问题、设计混乱。
- 本地化日期时间API:
- LocalDate
- LocalTime
- LocalDateTime:类似于Calendar
- Instant:时间戳,类似于Date。
- ZoneId:时区。
- Date、Instant、LocalDateTime的转换。
- DateTimeFormatter:格式化类。
LocalDateTime
//LocalDateTime 日期不可修改 相当于Calendar
public class Demo1 {
public static void main(String[] args) {
//当前时间
LocalDateTime localDate = LocalDateTime.now();
System.out.println(localDate);
//昨天
LocalDateTime localDate1 = localDate.minusDays(1);
LocalDateTime localDate2 = localDate.plusDays(-1);
//明天
LocalDateTime localDate3 = localDate.plusDays(1);
System.out.println("-----------------");
//指定日期和时间的对象
LocalDateTime of = LocalDateTime.of(1997, 7, 1, 1, 1, 1);
System.out.println(of);
System.out.println("-----------------");
//获取日期和时间信息
localDate.getYear();
localDate.getMonthValue();
localDate.getDayOfMonth();
localDate.getHour();
localDate.getMinute();
System.out.println("-------------------");
//设置日期和时间(不可变)
LocalDateTime localDate4 = localDate.withMonth(2);
System.out.println(localDate);
System.out.println(localDate4);
System.out.println("--------------------");
Date date = new Date();
System.out.println(date);
date.setTime(System.currentTimeMillis() - 60 * 60 * 24 * 1000);
System.out.println(date);
}
}
Instant
//Instant 时间戳(1970-现在) 相当于Date
//毫秒值没有问题,时区显示不同
class Demo2 {
public static void main(String[] args) throws InterruptedException {
Instant now = Instant.now();
System.out.println(now);
System.out.println("秒" + now.getEpochSecond());
System.out.println("毫秒" + now.toEpochMilli());
//昨天
System.out.println(now.minusMillis(60 * 60 * 24 * 1000));
//明天
System.out.println(now.plusMillis(60 * 60 * 24 * 1000));
//可以用来计时
Instant start = Instant.now();
Thread.sleep(3000);
Instant end = Instant.now();
System.out.println(end.toEpochMilli() - start.toEpochMilli());
}
}
ZoneId
class Demo3 {
public static void main(String[] args) {
//ZoneId 时区类
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
for (String zoneId : zoneIds) {
System.out.println(zoneId);
}
//获取默认时区
System.out.println(ZoneId.systemDefault());
}
}
Date、Instant、LocalDateTime的转换
class Demo4 {
public static void main(String[] args) {
//演示转换
//(1) LocalDateTime -> Instant -> Date
LocalDateTime now = LocalDateTime.now();
Instant instant = now.atZone(ZoneId.systemDefault()).toInstant();
Date from = Date.from(instant);
//(2) Date -> Instant -> LocalDateTime
Instant instant1 = from.toInstant();
LocalDateTime localDateTime = instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
}
}
DateTimeFormatter
class Demo5{
public static void main(String[] args) {
//时间格式化类 DateTimeFormatter
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//日期 -> 字符串
LocalDateTime now = LocalDateTime.now();
System.out.println(formatter.format(now));
//字符串 ——> 日期
LocalDateTime parse = LocalDateTime.parse("1882-11-10 21:12:12", formatter);
System.out.println(parse);
}
}
[/wppay]