Java8特性
1.Java8概述
- Java(JDK1.8)是Java语言开发的一个主要版本
- 支持Lambda表达式
- 函数式接口
- 新的StreamAPI
- 新的日期API
- 其他特性
2.Lambda表达式
-
Lambda表达式:特殊的匿名内部类,语言更简洁
-
Lambda表达式允许把函数作为一个方法的参数(函数作为方法参数传递),将代码像数据一样传递
-
基本语法:
<函数式接口><变量名>=(参数1,参数2…)->{//方法体};
Lambda Demo
public static void main(String[] args) {
//匿名内部类对象
Runnable runnable=new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"is executor.");
}
};
//Lambda优化匿名内部类,
Runnable runnable1=()->{
System.out.println(Thread.currentThread().getName()+"is executor.");
};
//Lambda表达式中只有一条语句,省略方法的{}.
Runnable runnable2=()-> System.out.println(Thread.currentThread().getName()+"is executor.");
new Thread(runnable).start();
new Thread(runnable1).start();
new Thread(runnable2).start();
Comparator<String>comparator=new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
};
//Lambda优化
Comparator<String>comparator1=(String o1,String o2)->{
return o1.compareTo(o2);
};
//Lambda表达式中只有一条语句,省略方法的{},如果有返回值 return省略
Comparator<String>comparator2=(String o1,String o2)->o1.compareTo(o2);
//参数中类型可以推断出来,可以省略
Comparator<String>comparator3=(o1,o2)->o1.compareTo(o2);
//方法引用简化
Comparator<String>comparator4=String::compareTo;
}
- Lambda引入了引得操作符:->(箭头操作符),->将表达式分成两部分
- 左侧:(参数1,参数2.。)表示参数列表
- 右侧:{}内不是方法体
- 注意事项
- 形参列表的数据类型会自动推断
- 如果形参列表为空,只需保留();
- 如果形参只有1个,()可以省略,只需要参数的名称即可。
- 如果执行语句只有一句,且无返回值,{}可以省略,若有返回值,则若想去{},则必须同时省略return,且执行语句也保证只有一句。
- Lambda不会生成一个单独的内部类。
3.函数式接口
- 如果一个接口只有一个抽象方法,则该接口称之为函数式接口,函数式接口可以使用Lambda表达式,Lambda表达式会被匹配到这个抽象方法上。
- @FunctionInterface 注解检测接口是否符合函数式接口。
//MyPredicate.java
@FunctionalInterface
public interface MyPredicate<T> {
public abstract boolean test(T t);
}
//Usb.java
@FunctionalInterface
public interface Usb {
public abstract void work();
}
//Main.java
public static void main(String[] args) {
Usb usb = new Usb() {
@Override
public void work() {
System.out.println("usb begin work.");
}
};
Usb usb1 = () -> System.out.println("usb begin work.");
MyPredicate<String> myPredicate = new MyPredicate<String>() {
@Override
public boolean test(String s) {
if (s.startsWith("H")) {
return true;
}
return false;
}
};
MyPredicate<String> myPredicate1 = s -> {
if (s.startsWith("H")) {
return true;
}
return false;
};
}
常用函数式接口
函数式接口 | 参数类型 | 返回类型 | 说明 |
---|---|---|---|
Consumer消费型接口 | T | void | void accpet(T t);对类型为T的对象应用操作 |
Supplier供给型接口 | 无 | T | T get();返回类型为T的对象 |
Function<T,R>函数型接口 | T | R | Rapply(T t);对类型为T的对象应用操作,并返回类型为R类型的对象。 |
Predicate断言型接口 | T | boolean | boolean test(T t);确定类型为T的对象是否满足条件,并返回boolean类型 |
public class Main {
public static void main(String[] args) {
/**
* 演示函数式接口的使用
* Consumer 消费型
* Supplier 供给型
* Function 函数型
* Predicate 断言型
*/
happy(new Consumer<Double>() {
@Override
public void accept(Double d) {
System.out.println("attend a party , and cast " + d);
}
}, 1000);
happy(d -> System.out.println("attend a part, and cast " + d), 1000);
happy(d -> System.out.println("and to waste a foot " + d), 2000);
int[] nums = getNums(() -> new Random().nextInt(100), 5);
System.out.println(Arrays.toString(nums));
String result = handlerString(s -> s.toUpperCase(), "hello");
System.out.println(result);
String result2 = handlerString(s -> s.trim(), "java pthron ");
System.out.println(result2);
ArrayList<String> names = new ArrayList<>();
names.add("张三");
names.add("张无忌");
names.add("赵敏");
ArrayList<String> result3 = filter(s -> s.startsWith("张"), names);
System.out.println(result3);
}
//Consumer 消费型
public static void happy(Consumer<Double> consumer, double money) {
consumer.accept(money);
}
//Supplier 供给型
public static int[] getNums(Supplier<Integer> supplier, int length) {
int[] arr = new int[length];
for (int i = 0; i < arr.length; i++) {
arr[i] = supplier.get();
}
return arr;
}
//Function 函数型
public static String handlerString(Function<String, String> function, String str) {
String apply = function.apply(str);
return apply;
}
//Predicate 断言型
public static ArrayList<String> filter(Predicate<String> predicate, ArrayList<String> names) {
ArrayList<String> list = new ArrayList<>();
for (String s : names) {
if (predicate.test(s)) {
list.add(s);
}
}
return list;
}
}
4.方法引用
- 方法引用是Lambda表达式的一种简写形式。如果Lambda表达式方法体中。只是调用一种特定的已经存在的方法,则可以使用方法引用。
- 常见形式
- 对象::实例方法
- 类::静态方法
- 类:: 实例方法
- 类::new
public class Main {
public static void main(String[] args) {
//1.对象::实例方法
//消费型接口
// 1)Lambda中只调用了一个方法 System.out.println()方法
// 2)调用方法的形式(参数和返回值)和接口一样
Consumer<String> consumer = s -> System.out.println(s);
//使用方法引用优化,提供新的操作符::
Consumer<String> consumer1 = System.out::println;
consumer1.accept("hello");
//类::静态方法
//1)Lambda中只调用一个方法,2)调用方法compare的形式(参数和返回值)和接口一样
// Comparator<Integer>comparator=(o1,o2)->{
// return Integer.compare(o1, o2);
// };
Comparator<Integer> comparator = (o1, o2) -> Integer.compare(o1, o2);
Comparator<Integer>comparator=Integer::compare;
//类::实例方法
//1)Lambda中只调用一个方法 2)有一个参数作为Lambda中方法的调用者,其他作为参数传递
Comparator<String> comparator2 = (o1, o2) -> o1.compareTo(o2);
Comparator<String> comparator3 = String::compareTo;
//Employee.java
//1)Lambda中只调用一个方法 2)有一个参数作为Lambda中方法的调用者,其他作为参数传递
Function<Employee, String> function = e -> e.getName();
Function<Employee, String> function1 = Employee::getName;
System.out.println(function.apply(new Employee()));
//类::new
//1)Lambda中只调用用一个构造方法 2)构造方法中的参数和接口中的参数一样
Supplier<Employee> supplier = () -> new Employee();
Supplier<Employee> supplier1 = Employee::new;
MySupplier<Employee> supplier2 = (n, a, s) -> new Employee(n, a, s);
MySupplier<Employee> supplier3 = Employee::new;
System.out.println(supplier3.get("dmeodong", 12, 12.0));
//数组
//元素类型[]::new
// 1) Lambda中只创建数组 2)参数作为数组的长度
Function<Integer,int[]>function2=n->new int[n];
Function<Integer,int[]>function3=int[]::new;
int[] apply = function3.apply(4);
}
}
//MySupplier.java
public interface MySupplier <T>{
T get(String name,int age,double salary);
}
- 问题1:上面Systme.out.println()为什么可以使用方法引用
//消费类型只有参数而无返回值
//查看System.out的源码发现out是一个PrintStream类,
public final static PrintStream out = null;
//而且PrintStream实现了println(String s)方法且无返回值,
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
//所以是同类型的可以实现
//突然看了一下Integer的源码发现Integer只实现了Comparable接口并没有实现Comparator接口,为什么有
//compare方法,还真有,Integer自己写的
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
- 一般类排序都会实现 Comparable接口中的compareTo方法
- 比较器是Comparator接口实现compare方法
- 如果想改变排序规则Cpmarator的优先级比Comparable的高。
Comparator 和 Comparable 比较
Comparable是排序接口;若一个类实现了Comparable接口,就意味着“该类支持排序”。
而Comparator是比较器;我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。
我们不难发现:Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。
5.Stream API
-
流(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方法。
public static void main(String[] args) {
//1)创建流
//1.1通过Collection或parallelStream()方法
ArrayList<String> list = new ArrayList<>();
list.add("waterlemon");
list.add("peach");
list.add("banana");
list.add("apple");
//获取串行流(单线程)
// Stream<String> stream = list.stream();
// stream.forEach(s -> System.out.println(s));
//获取并行流(多线程)
Stream<String> stream = list.parallelStream();
stream.forEach(System.out::println);
//1.2通过Arrays类的stream()方法。
IntStream stream1 = Arrays.stream(new int[]{1, 2, 8, 4, 6});
stream1.sorted().forEach(System.out::println);
//1.3通过Stream类接口的of(),iterate(),generate()方法
Stream<String> stream2 = Stream.of(new String[]{"北京", "南京", "huoche"});
stream2.filter(s -> s.endsWith("京")).forEach(System.out::println);
//无限迭代流
Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);
iterate.limit(100).forEach(System.out::println);
//无限生成流
Stream<Integer> generate = Stream.generate(() -> new Random().nextInt(100));
generate.limit(10).forEach(System.out::println);
//1.4通过IntStream,LongStream,DoubleStream接口中的of,range,reangeClosed方法
IntStream intStream = IntStream.of(new int[]{10, 2, 30, 4});
intStream.forEach(System.out::println);
IntStream range = IntStream.range(0, 100);
range.forEach(System.out::println);
IntStream intStream1 = IntStream.rangeClosed(0, 100);
intStream1.forEach(System.out::println);
}
中间操作,终止操作
- 中间操作
- filter,limit,skip,distinct,sorted
- map
- parallel
- 终止操作
- forEach,min,max,count
- reduce,collect
public static void main(String[] args) {
//集合
ArrayList<Employee> employees = new ArrayList<>();
employees.add(new Employee("demodong1", 18, 2000));
employees.add(new Employee("demodong2", 15, 100000));
employees.add(new Employee("demodong3", 12, 20000900));
employees.add(new Employee("demodong4", 10, 20));
employees.add(new Employee("demodong5", 10, 20));
//filter过滤
employees.stream()
.filter(x -> x.getAge() > 15)
.forEach(System.out::println);
employees.stream()
.filter(s -> s.getSalary() > 5000)
.forEach(System.out::println);
//limit 限制数据个数
employees.stream()
.limit(2)
.forEach(System.out::println);
//skip 逃过n个元素
employees.stream()
.skip(2)
.forEach(System.out::println);
//distinct 去掉重复的 hashCode和equals
employees.stream()
.distinct()
.forEach(System.out::println);
//sorted 排序
employees.stream()
.sorted((o1, o2) -> Double.compare(o1.getSalary(), o2.getSalary()))
.forEach(System.out::println);
}
public static void main(String[] args) {
ArrayList<Employee> employees = new ArrayList<>();
employees.add(new Employee("dmeodong1", 12, 200));
employees.add(new Employee("dmeodong2", 13, 200));
employees.add(new Employee("dmeodong3", 12, 500));
employees.add(new Employee("dmeodong4", 121, 400));
employees.add(new Employee("dmeodong5", 19, 300));
employees.add(new Employee("dmeodong6", 10, 100));
//map 映射
//获取所有人都姓名
employees.stream()
.map(Employee::getName)
.forEach(System.out::println);
//parallel 并行流
employees.stream()
.filter(s -> s.getAge() > 10)
.sorted(((o1, o2) -> Double.compare(o1.getSalary(), o2.getSalary())))
.distinct()
.forEach(System.out::println);
//min max count
//Options是一个元素容易,防止空指针异常
Optional<Employee> min = employees.stream()
.min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(min.get());
Optional<Employee> max = employees.stream()
.max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(max.get());
Optional<Employee> count = employees.stream()
.min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(count);
//reduce ,collect
//reduce:规约,统计
Optional<Integer> reduce = employees.stream()
.map(e1 -> (int) e1.getSalary())
.reduce((x, y) -> x + y);
System.out.println(reduce);
//collect:收集
//收集所有人的姓名
List<String> collect = employees.stream()
.map(e -> e.getName())
.collect(Collectors.toList());
System.out.println(collect.toString());
//平均工资
Double collect1 = employees.stream()
.map(e -> e.getSalary())
.collect(Collectors.averagingDouble(s -> s));
System.out.println(collect1);
}
6.新时间API
- 本地化日期时间 API:
- LocalDate
- LocalTime
- LocalDateTime
- Instant:时间戳
- Zoneld:时区
- Date,Instant.LocalDateTime的转换
- DateTimeFormatter:格式化类
public static void main(String[] args) {
//创建本地日期和时间
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime.getYear());
System.out.println(localDateTime.getMonth().getValue());
System.out.println(localDateTime.getDayOfMonth());
System.out.println(localDateTime.getHour());
System.out.println(localDateTime.getMinute());
System.out.println(localDateTime.getSecond());
//昨天
LocalDateTime yesterday = localDateTime.minusDays(1);
//明天
LocalDateTime tomorrow = LocalDateTime.of(2020, 8, 14, 10, 13, 13);
//本月第几天
LocalDateTime localDateTime1 = localDateTime.withDayOfMonth(10);
System.out.println(localDateTime1);
}
//instant:时刻,瞬间: 从1970年1月1日0:0:0
Instant instant = Instant.now();
System.out.println("second" + instant.getEpochSecond());
System.out.println("millssecond" + instant.toEpochMilli());
//昨天
Instant yesterday = instant.minusMillis(24 * 60 * 60 * 1000);
//明天
Instant tomorrow = instant.plus(1, ChronoUnit.DAYS);
System.out.println(instant);
System.out.println(yesterday);
System.out.println(tomorrow);
// System.out.println(instant.get(ChronoField.YEAR_OF_ERA));
// System.out.println(instant.get(ChronoField.MONTH_OF_YEAR));
// System.out.println(instant.get(ChronoField.DAY_OF_MONTH));
//Date
//Date --> Instant ---> LocalDateTime
Date date = new Date();
Instant instant1 = date.toInstant();
System.out.println(date);
System.out.println(instant1);
//时区 ZoneId
System.out.println(ZoneId.systemDefault());
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
for (String availableZoneId : availableZoneIds) {
System.out.println(availableZoneId);
}
LocalDateTime localDateTime = instant1.atZone(ZoneId.systemDefault()).toLocalDateTime();
//LocalDateTime ->instance ->Date
Instant instant2 = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
Date date1 = Date.from(instant2);
//创建时间格式化器
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//把日期改为字符串
LocalDateTime now = LocalDateTime.now();
String format = dtf.format(now);
System.out.println(format);
//字符串改为日期
LocalDateTime parse = LocalDateTime.parse("2020-08-13 17:24:00",dtf);
System.out.println(parse);