原创
Java8新特性
温馨提示:
本文最后更新于 2018年07月06日,已超过 2,331 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我。
Java8新特性之函数式接口以及default方法
函数式接口
- jdk8中新增了函数式接口,在一个接口中只有一个抽象方法的接口被称为函数式接口。
- 例如java.lang.Runnable,java.util.concurrent.Callable。
- jdk8中新增了@FunctionalInterface注解来标注一个函数式接口。
default方法
- jdk8中新增了default方法,jdk8之前接口中的方法必须都是抽象的,在jdk8中允许接口中定义非抽象方法,
- 在接口中的非抽象方法上使用default修饰即可,比如在jdk8中新增了一个函数式接口:java.util.function。
- java8中打破了接口中的方法必须都是抽象的这一规范,有一个好处就是可以提高程序的兼容性,
- 在java.lang.Iterable接口中新增了forEach方法,该方法就是使用default修饰的。
- 在接口中定义default方法可以变相的让java支持"多继承"。
package com.lzhpo.functioninterface;
/**
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
@FunctionalInterface //自定义函数接口
public interface MyInterface {
void m1(int a,int b);
default String m2(String s){
return null;
}
default void m3(){
}
}
Java8新特性之Lambda表达式
Lambda语法
lambda 表达式的语法格式如下:
(parameters) -> expression 或 (parameters) ->{ statements; }
以下是lambda表达式的重要特征:
可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
可以将lambda看做是一个匿名方法,lambda只能用于函数式接口。
(类型 参数, 类型 参数, …, 类型 参数) -> { 代码块; return 结果; }
主要由这几个符合构成:
() -> {}
lambda优点:使用lambda表达式可以编写出比匿名内部类更简洁的代码。
lambda表达式为什么只能用于函数式接口中?
lambda表达式实际上就是重写了接口中的抽象方法,在函数式接口中只有一个抽象方法,此时编译器会认定重写的就是该唯一的抽象方法。
倘若一个接口中有多个抽象方法,而lambda表达式是没有匿名的,编译器就无法判断其重写的是哪个抽象方法了。
简单示例:
Lambda 表达式的简单例子:
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
使用Lambda表达式和不使用Lambda表达式比较
package com.lzhpo.lambda;
import com.lzhpo.functioninterface.MyInterface;
/**
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class LambdaDemo1 {
public static void main(String[] args) {
/**
* 不使用Lambda表达式
*/
System.out.println("======不使用Lambda表达式======");
MyInterface oldType = new MyInterface() {
@Override
public void m1(int a, int b) {
System.out.println(a + b);
}
};
oldType.m1(99,66);
/**
* 使用Lambda表达式
*/
System.out.println("======使用Lambda表达式======");
MyInterface newType = (int a,int b) -> {
System.out.println(a + b);
};
// 编译器都可以从上下文环境中推断出lambda表达式的参数类型,因此可以省略参数类型
/* MyInterface newType = (a, b) -> {
System.out.println(a + b);
}; */
newType.m1(99,66);
}
}
Lambda在多线程中的写法
package com.lzhpo.lambda;
/**
* Lambda在多线程中的写法:
*
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class LambdaDemo2 {
public static void main(String[] args) {
/**
* 不使用Lambda的写法
*/
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("no lambda");
}
}).start();
/**
* lambda写法
*
* 因为Thread类中接收Runnable类型的对象,所以编译器会识别出lambda表达式是Runnable对象
*/
new Thread(() -> {
System.out.println("lambda");
}).start();
}
}
foreach方法
在jdk8中的java.lang.Iterable接口中新增了非抽象的forEach方法。
可以使用该方法配合lambda来遍历集合。
package com.lzhpo.foreach;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
//使用Lambda遍历集合
public class Demo {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
/**
* java8之前
*/
System.out.println("======java8之前======");
for (Integer i:list) {
System.out.print(i + " ");
}
System.out.println();
/**
* java8之后
*
* 在Iterator接口中新增了非抽象的foreach方法。
*/
System.out.println("======java8之后======");
list.forEach((Integer n) -> {
System.out.print(n + " ");
});
System.out.println();
//如果在lambda表达式中只有一个参数一行语句的时候,可以简写为下面格式
list.forEach(n -> System.out.print(n + " "));
System.out.println();
//Java 8新增方法引用,方法引用由::双冒号操作符标示
list.forEach(System.out::println);
}
}
方法引用
方法引用主要是用来简写lambda表达式,
有些lambda表达式里面仅仅是执行一个方法调用,
这时使用方法引用可以简写lambda表达式。
package com.lzhpo.usefunction;
import java.util.Arrays;
import java.util.Comparator;
/**
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class Demo {
public static void main(String[] args) {
/**
* 一共有四种类型的方法引用:
*
* 静态方法引用,类名::方法名
* 某个对象的引用,对象变量名::方法名
* 特定类的任意对象的方法引用,类名::方法名
* 构造方法,类名::new
*/
Integer[] num = new Integer[]{66,23,99,56};
/**
* 不使用Lambda
*/
Arrays.sort(num, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
});
/**
* 使用Lambda
*/
Arrays.sort(num,(x,y) -> Integer.compare(x,y));
/**
* 方法引用
*/
Arrays.sort(num,Integer::compare);
}
}
构造方法的引用
Car:
package com.lzhpo.usefunction.useconstructionmethod;
import java.util.function.Supplier;
/**
* 构造方法的引用:
* 先创建一个Car类型,添加一个buy方法,
* 为了能够使用lambda表达式,这里使用java.util.function.supplier接口,
* 这个接口是java8新增的一个函数式接口,里面只有一个抽象的get方法。
*
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class Car {
public static Car buy(Supplier<Car> s){
//通过get方法传入的Car类型的对象
return s.get();
}
}
TestCar:
package com.lzhpo.usefunction.useconstructionmethod;
/**
* 构造方法引用
*
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class TestCar {
public static void main(String[] args) {
Car car = Car.buy(Car::new);
System.out.println(car);
}
}
Java8新特性之Stream
Stream简介
- jdk8中新增stream API,需要注意的是该stream跟之前学习的IO流没有关系,
- 这个stream主要是用来处理集合数据的,可以将其看做是一个高级迭代器。
- 在Collection接口中新增了非抽象的stream方法来获取集合的流。
- 使用stream后可以写出更简洁的代码来处理集合中的数据。
使用Stream示例
Student:
package com.lzhpo.stream.useStream;
/**
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class Student {
private String name;
private int score;
public Student(){
}
public Student(String name, int score) {
super();
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "[姓名=" + name + ", 分数=" + score + "]";
}
}
TestStudent:
package com.lzhpo.stream.useStream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class TestStudent {
public static void main(String[] args) {
List<Student> stuList = new ArrayList<>(10);
stuList.add(new Student("刘一", 85));
stuList.add(new Student("陈二", 90));
stuList.add(new Student("张三", 98));
stuList.add(new Student("李四", 88));
stuList.add(new Student("王五", 83));
stuList.add(new Student("赵六", 95));
stuList.add(new Student("孙七", 87));
stuList.add(new Student("周八", 84));
stuList.add(new Student("吴九", 100));
stuList.add(new Student("郑十", 95));
/**
* 需求:列出90分以上的学生姓名,并按照分数降序排序
*/
/**
* 以前的写法,代码较多,每个操作都需要遍历集合
*/
List<Student> result1 = new ArrayList<>(10);
System.out.println("======以前的写法======");
//遍历集合获取分数大于90分以上的学生并存放到新的List中
for (Student s : stuList) {
if (s.getScore() >= 90){
result1.add(s);
}
}
//对List进行降序排序
result1.sort(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return Integer.compare(o2.getScore(),o1.getScore());
}
});
//打印结果
System.out.println(result1);
/**
* 使用Stream的写法:
*
* 1.获取集合的stream对象
* 2.使用filter方法完成过滤
* 3.使用sort方法完成排序
* 4.使用collect方法将处理好的stream对象转换为集合对象
*/
System.out.println("======使用Stream======");
result1 = stuList.stream()
// filter:Predicate是一个函数式接口(@FunctionalInterface)
.filter(s -> s.getScore() >= 90)
.sorted(Comparator.comparing(Student::getScore).reversed())
.collect(Collectors.toList());
System.out.println(result1);
}
}
Map和Reduce
学过大数据的就知道,对MapReduce很敏感。
- map用来归类,结果一般是一组数据,比如可以将list中的学生分数映射到一个新的stream中。
- reduce用来计算值,结果是一个值,比如计算最高分。
简单示例
Student:
package com.lzhpo.stream.useStream;
/**
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class Student {
private String name;
private int score;
public Student(){
}
public Student(String name, int score) {
super();
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "[姓名=" + name + ", 分数=" + score + "]";
}
}
InitData:
package com.lzhpo.stream.mapreduce;
import com.lzhpo.stream.useStream.Student;
import java.util.ArrayList;
import java.util.List;
/**
* 初始化数据
*
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class InitData {
public static List<Student> getStudent(){
List<Student> stuList = new ArrayList<>(10);
stuList.add(new Student("刘一", 85));
stuList.add(new Student("陈二", 90));
stuList.add(new Student("张三", 98));
stuList.add(new Student("李四", 88));
stuList.add(new Student("王五", 83));
stuList.add(new Student("赵六", 95));
stuList.add(new Student("孙七", 87));
stuList.add(new Student("周八", 84));
stuList.add(new Student("吴九", 100));
stuList.add(new Student("郑十", 95));
return stuList;
}
}
Demo:
package com.lzhpo.stream.mapreduce;
import com.lzhpo.stream.useStream.Student;
import java.util.List;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class Demo {
public static void main(String[] args) {
//初始化List数据同上
List<Student> list = InitData.getStudent();
/**
* 打印初始数据,方便对比。
*/
List<Integer> scoreInit = list.stream()
.map(Student::getScore)
.collect(Collectors.toList());
System.out.println("初始分数:" + scoreInit);
/**
* 使用map方法获取list数据中的name
*/
List<String> names = list.stream()
.map(Student::getName)
.collect(Collectors.toList());
System.out.println("使用map方法获取list数据中的name:" + names);
/**
* 使用map方法获取list数据中的names的长度
*/
List<Integer> length = list.stream()
.map(Student::getName)
.map(String::length)
.collect(Collectors.toList());
System.out.println("使用map方法获取list数据中的names的长度:" + length);
/**
* 将每人的分数减10
*/
List<Integer> score = list.stream()
.map(Student::getScore)
.map(i -> i - 10)
.collect(Collectors.toList());
System.out.println("将每人的分数减10:" + score);
/**
* 计算学生总分
*/
Integer totalScore1 = list.stream()
.map(Student::getScore)
.reduce(0,(a,b) -> a + b);
System.out.println("计算学生总分:" + totalScore1);
/**
* 计算最高分和最低分
*
* 注意:
* Optional:
* - Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
* - Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
* - Optional 类的引入很好的解决空指针异常。
*/
Optional<Integer> max = list.stream()
.map(Student::getScore)
.reduce(Integer::max);
Optional<Integer> min = list.stream()
.map(Student::getScore)
.reduce(Integer::min);
System.out.println("最高分:" + max.get());
System.out.println("最低分:" + min.get());
/**
* 计算平均分
*/
OptionalDouble avgScore = list.stream()
.mapToInt(Student::getScore)
.average();
System.out.println("平均分:" + avgScore.getAsDouble());
/**
* 其它操作:
*/
//生成随机数(1,100)
IntStream num = IntStream.rangeClosed(1,100);
//计算1-100之间的数字中偶数的个数
long count = IntStream.rangeClosed(1,100)
.filter(n -> n%2 == 0)
.count();
System.out.println("计算1-100之间的数字中偶数的个数:" + count);
}
}
运行结果:
初始分数:[85, 90, 98, 88, 83, 95, 87, 84, 100, 95]
使用map方法获取list数据中的name:[刘一, 陈二, 张三, 李四, 王五, 赵六, 孙七, 周八, 吴九, 郑十]
使用map方法获取list数据中的names的长度:[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
将每人的分数减10:[75, 80, 88, 78, 73, 85, 77, 74, 90, 85]
计算学生总分:905
最高分:100
最低分:83
平均分:90.5
计算1-100之间的数字中偶数的个数:50
创建流
package com.lzhpo.stream.createflow;
import java.util.Arrays;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* 创建流
*
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class Demo {
public static void main(String[] args) {
/**
* 使用Stream.of创建流
*/
Stream<String> stringStream = Stream.of("i","love","you");
stringStream.map(String::toUpperCase).forEach(System.out::println);
/**
* 使用数组创建流
*/
int[] arr = new int[]{99,66,55,77,88,100};
IntStream intStream = Arrays.stream(arr);
int sum = intStream.sum();//求和
System.out.println("求和:" + sum);
/**
* 由函数生成流,创建无限流
*/
Stream.iterate(0,n -> n + 2)
.limit(10)
.forEach(System.out::println);
}
}
Java8新特性之Optional类
Optional简介
- 空指针异常是在学习和开发中最常见的问题之一,
- 为了解决这个问题,在java8中新增了Optional类。
- 这个类在java.util包下,使用这个类可以更好的支持函数式编程,
- 并且可以简化以前对null的判断。
简单示例
package com.lzhpo.optional;
import com.lzhpo.stream.mapreduce.InitData;
import com.lzhpo.stream.useStream.Student;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class Demo {
public static void main(String[] args) {
/**
* 初始数据
*/
List<Student> list = InitData.getStudent();
List<Integer> core = list.stream()
.map(Student::getScore)
.collect(Collectors.toList());
System.out.println("初始分数:" + core);
/**
* 例1:计算成绩小于60分的学生分数总和。
* 因为没有成绩小于60分的。
*/
List<Student> studentList = InitData.getStudent();
Optional<Integer> count = studentList.stream()
.filter(s -> s.getScore() < 60)
.map(Student::getScore)
.reduce((a,b) -> a + b);
//如果要是空(无),返回0
System.out.println("成绩小于60分的学生成绩总和:" + count.orElse(0));
/**
* 例2:
*/
Map<Integer,String> map = new HashMap<>();
map.put(1001, "篮球");
map.put(1002, "足球");
map.put(1003, "羽毛球");
map.put(1004, "乒乓球");
//没有1005,返回无
String sport = Optional.ofNullable(map.get(1005))
.orElse("无");
System.out.println("获取编号为1005的运动项目:" + sport);
}
}
Java8新特性之日期处理
LocalDate
package com.lzhpo.data;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
/**
* LocalDate:
*
* LocalDate类只能操作日期相关的数据,不包含时间。
*
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class LocalDateDemo {
public static void main(String[] args) {
//今天的日期,不包括时间
LocalDate date1 = LocalDate.now();
System.out.println("今天的日期,不包括时间:" + date1);
int year = date1.getYear();
int month = date1.getMonthValue();
int day = date1.getDayOfMonth();
//格式化日期
String date2 = date1.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"));
System.out.println("格式化日期:" + date2);
//判断闰年
boolean leap = date1.isLeapYear();
System.out.println("今年是否是闰年:" + leap);
//获取该月份有多少天
int len = date1.lengthOfMonth();
//设置日期
LocalDate date3 = LocalDate.parse("2016-06-15");
LocalDate date4 = LocalDate.of(216,06,15);
//判断两个日期是否相等
if (date4.equals(date3)){
System.out.println("日期相等");
}
//设置一周后的日期
LocalDate nextWeek = date1.plus(1, ChronoUnit.WEEKS);
System.out.println("今天:" + date1);
System.out.println("一周后:" + nextWeek);
}
}
LocalTime
package com.lzhpo.data;
import java.time.LocalTime;
/**
* LocalTime:
*
* LocalTime类只能操作时间相关的数据,不包含日期。
*
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class LocalTimeDEmo {
public static void main(String[] args) {
//获取当前时间
LocalTime time1 = LocalTime.now();
LocalTime time2 = LocalTime.now().withNano(0);//去除毫秒
System.out.println("当前时间:" + time2);
//2小时后的时间
LocalTime newTime = time1.plusHours(2);
System.out.println("两小时后:" + newTime);
//设置时间
LocalTime time3 = LocalTime.of(6, 30, 28);
LocalTime time4 = LocalTime.parse("18:20:36");
}
}
LocalDateTime
package com.lzhpo.data;
import java.time.LocalDateTime;
/**
* LocalDateTime:
*
* LocalDateTime类可以处理日期和时间的数据。
*
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class LocalDateTimeDemo {
public static void main(String[] args) {
//获取当前日期和时间
LocalDateTime date1 = LocalDateTime.now();
System.out.println(date1);
LocalDateTime date2 = LocalDateTime.of(2017, 7, 11, 12, 30, 20);
System.out.println(date2);
}
}
Duration和Period
- Duration类用来获取两个LocalTime相差的时间。
- Period类用来获取两个LocalDate相差的日期。
示例1
package com.lzhpo.data.durationperiod;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
/**
* Duration和Period
*
* Duration类用来获取两个LocalTime相差的时间。
* Period类用来获取两个LocalDate相差的日期。
*
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class Demo {
public static void main(String[] args) {
//计算两个LocalTime相差的时间
LocalTime time1 = LocalTime.of(7, 20, 00);
LocalTime time2 = LocalTime.of(7, 30, 10);
Duration duration = Duration.between(time1, time2);
System.out.println(duration.getSeconds());
//计算两个LocalDate相差的日期
LocalDate date1 = LocalDate.of(2017, 7, 11);
LocalDate date2 = LocalDate.of(2017, 7, 13);
Period period = Period.between(date1, date2);
System.out.println(period.getDays());
}
}
示例2
package com.lzhpo.data.durationperiod;
import java.time.*;
/**
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class Example1 {
public static void main(String[] args) {
/**
* 计算祖国从建国到现在过了多少年多少月多少日了
*/
System.out.println("================计算祖国从建国到现在过了多少年多少月多少日================");
// 建国日期
LocalDate begin1 = LocalDate.of(1949, 10, 1);
// 今天日期
LocalDate end1 = LocalDate.now();
Period period = Period.between(begin1, end1);
System.out.println("祖国已成立:");
System.out.println(period.getYears() + "年");
System.out.println(period.getMonths() + "月");
System.out.println(period.getDays() + "天");
System.out.println();
/**
* 计算祖国成立多少天
*/
System.out.println("================计算祖国成立多少天================");
LocalDate date = LocalDate.of(1949, 10, 1);
LocalTime time = LocalTime.of(7, 20, 00);
LocalDateTime begin2 = LocalDateTime.of(date, time);
LocalDateTime end2 = LocalDateTime.now();
Duration between = Duration.between(begin2, end2);
System.out.println("祖国成立:" + between.toDays() + "天");
System.out.println();
/**
* 设定时区
*/
System.out.println("================设定时区================");
//获取本地的时区时间
ZonedDateTime now = ZonedDateTime.now();
System.out.println(now);
//设定时区为美国洛杉矶
ZoneId zone = ZoneId.of("America/Los_Angeles");
//获取指定的时区时间
ZonedDateTime usa = ZonedDateTime.now(zone);
System.out.println(usa);
}
}
- 本文标签: Java
- 本文链接: http://www.lzhpo.com/article/70
- 版权声明: 本文由lzhpo原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权