16.Java 8 的新特性
一、Lambda表达式
- 举例:(o1,o2) -> Interger.compare(o1,o2);
- 格式:
- -> : lambda操作符 或 箭头表达式
- ->左边 :lambda形参列表(其实就是接口中的抽象方法的形参列表)
- ->右边 : lambda体(其实就是重写的抽象方法的方法体)
- lambda表达式的本质:作为函数式接口的实例
- 总结:
- ->左边:
- lambda形参列表的参数类型可以省略(类型推断);
- 如果lambda形参列表只有一个参数,其一对()也可以省略
- ->右边:
- lambda应该使用一对{}包裹;
- 如果lambda体只有一条执行语句(可能是return语句),可以省略这一对{}和return关键字
- ->左边:
import java.util.Comparator;
import java.util.function.Consumer;
public class LambdaTest {
public static void main(String[] args) {
//语法格式一:无参,无返回值
Runnable r1 = () -> {
System.out.println("我爱中华!");
};
r1.run();
//语法格式二:Lambda需要一个参数,但是没有返回值
Consumer consumer1 = (String str) -> {
System.out.println(str);
};
consumer1.accept("谎言和誓言的区别是什么呢?");
//语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
Consumer consumer2 = (str) -> System.out.println(str);
consumer2.accept("一个是听的人当真了,一个是说的人当真了。");
//语法格式四:Lambda若只需要一个参数,参数的小括号可以省略
Consumer consumer3 = str -> System.out.println(str);
consumer3.accept("花开花落几时回?");
//语法格式五:Lambda需要两个或以上的参数,多条执行语句,并且可以有返回值
Comparator comparator1 = (o1,o2) -> {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
};
System.out.println(comparator1.compare(12, 21));
//语法格式六:当Lambda体只有一条执行语句时,return 与大括号若有,都可以省略
Comparator comparator2 = (o1,o2) -> o1.compareTo(o2);
System.out.println(comparator2.compare(12, 6));
}
}
二、函数式(Functional)接口
??如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。可以通过Lambda表达式来创建该接口的对象。若Lambda表达式抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽象方法上进行声明。可以通过在一个接口上使用@FunctionalInterface注解,这样可以检查它是否是一个函数时接口。同时javadoc也会包含一条声明,说明这个接口是一个函数式接口。匿名实现类表示都可以用Lambda表达式来写。
2.1、Java内置四大核心函数式接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer |
T | void | 对类型为T的对象应用操作,包含方法:void accept(T t) |
Supplier |
无 | T | 返回类型为T的对象,包含方法:T get() |
Function |
T | R | 对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t) |
Predicate |
T | boolean | 确定类型为T的对象是否满足某约束,并返回boolean值。包含方法:boolean test(T t) |
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
public class FunctionalInterface {
public static void main(String[] args) {
FunctionalInterface test = new FunctionalInterface();
List list = Arrays.asList("北京","天津","南京","西京","东京","开封");
test.happyTime(400,money -> System.out.println("今天共消费" + money));
List string = test.filterString(list,str -> str.contains("京"));
System.out.println(string);
}
public void happyTime(double money,Consumer consumer){
consumer.accept(money);
}
//根据给定的规则,过滤集合中的字符串。此规则由Predicate的方法决定
public List filterString(List list,Predicate predicate){
ArrayList filterList = new ArrayList<>();
for (String str : list) {
if(predicate.test(str)){
filterList.add(str);
}
}
return filterList;
}
}
2.2、其它接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
BiFunction |
T,U | R | 对类型为T,U参数应用操作,返回R类型的结果。,包含方法:R apply(T t,U u) |
UnaryOperator |
T | T | 对类型为T的对象进行一元运算,并返回T类型的结果。包含方法为:T apply(T t) |
BinaryOperator |
T,T | T | 对类型为T的对象进行二元运算,并返回T类型的结果。包含方法:T apply(T t1,T t2) |
BiConsumer |
T,U | void | 对类型为T,U参数应用操作。包含方法为:void accept(T t,U u) |
BiPredicate |
T,U | boolean | 包含方法:boolean test(T t,U u) |
ToIntFunction |
T | int | 计算int值的函数 |
ToLongFunction |
T | long | 计算long值的函数 |
ToDoubleFunction |
T | double | 计算double值的函数 |
IntFunction |
int | R | 参数为int类型的函数 |
LongFunction |
long | R | 参数为long类型的函数 |
DoubleFunction |
double | R | 参数为double类型的函数 |
三、方法引用与构造器引用
3.1、方法引用
??当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用。方法引用可以看做是Lambda表达式的深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法。方法引用要求实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!(针对情况一和情况二)格式:使用操作符“::”将类(或对象)与方法名分隔开来。当函数式接口方法的第一个参数是需要引用方法的调用者,并且第二个参数是需要引用方法的参数(或无参数)时,(针对情况三)格式:ClassName::methodName
如下三种主要使用情况
- 情况一:对象::实例方法名
- 情况二:类::静态方法名
- 情况三:类::实例方法名
import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
public class MethodReference {
public static void main(String[] args) {
//情况一:对象::实例方法
//Consumer中的 void accept(T t)
//PrintStream中的 void println(T t)
PrintStream printStream = System.out;
Consumer consumer = printStream::println;
consumer.accept("Sakura");
//情况二:类::静态方法
//Supplier中的 T get()
//Person中的 String gerName()
Person person = new Person("Sakura",10);
Supplier supplier = person::getAge;
System.out.println(supplier.get());
//情况三:类::非静态方法
//Comparator中的 int compare(T t1,T t2)
//Integer中的 int compare(T t1,T t2)
Comparator comparator = Integer::compare;
System.out.println(comparator.compare(10, 13));
System.out.println();
//Function中的 R apply(T t)
//Math中的 Long round(Double d)
Function fun1 = new Function() {
@Override
public Long apply(Double d) {
return Math.round(d);
}
};
System.out.println(fun1.apply(12.3));
Function fun2 = d -> Math.round(d);
System.out.println(fun2.apply(21.5));
Function fun3 = Math::round;
System.out.println(fun3.apply(33.7));
System.out.println();
//Comparator中的 int comapre(T t1,T t2)
//String中的 int t1.comparaTo(t2)
Comparator comparator2 = String::compareTo;
System.out.println(comparator2.compare("intel", "amd"));
//Function中的 R apply(T t)
//Person中的 String getName()
Function fun4 = Person::getName;
System.out.println(fun4.apply(person));
}
}
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this(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;
}
public String toString(){
return "Person{ name:" + name + ",age:" + age + "}";
}
}
3.2、构造器引用
??构造器引用与方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。抽象方法的返回值类型即为构造器所属的类的类型。
import java.util.function.Function;
import java.util.function.Supplier;
public class ConstructorReference {
public static void main(String[] args) {
//Supplier中的 T get()
Supplier supplier = Person::new;
System.out.println(supplier.get());
//Function中的 R apply(T t)
Function fun = Person::new;
System.out.println(fun.apply("Sakura"));
//BiFunction中 R apply(T t,U u)
BiFunction biFunction = Person::new;
System.out.println(biFunction.apply("Sakura", 9));
}
}
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this(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;
}
public String toString(){
return "Person{ name:" + name + ",age:" + age + "}";
}
}
3.3、数组引用
??可以把数组看做是一个特殊的类,则写法与构造器引用一致;
import java.util.Arrays;
import java.util.function.Function;
public class ArrayReferences {
public static void main(String[] args) {
Function fun1 = length -> new String[length];
String[] array1 = fun1.apply(5);
System.out.println(Arrays.toString(array1));
Function fun2 = String[]::new;
String[] array2 = fun2.apply(10);
System.out.println(Arrays.toString(array2));
}
}
四、强大的Stream API
4.1 Stream概述
??Stream API(java.util.stream)把真正的函数式接口编程风格引入到Java中。Stream是Java 8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作。简言之,Stream API提供了一种高效且易于使用的处理数据的方式。
- Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列
- Stream自己不会存储元素
- Stream不会改变源对象。相反,它会返回一个持有结果的新Stream
- Stream操作是延迟执行的。这意味着它会等到需要结果的时候才执行
创建Stream的操作三个对象
- 创建Stream:一个数据源(如:集合、数组),获取一个流
- 中间操作:一个中间操作链,对数据源的数据进行处理
- 终止操作(终端操作):一旦执行终止操作,就会执行中间操作链,并产生结果。之后,不会再被使用
4.2、创建Stream
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StreamTest {
public static void main(String[] args) {
//创建Stream方式一:通过集合
List list = Arrays.asList(1,2,3,4,5);
//default Stream stream():返回一个顺序流
Stream stream = list.stream();
//default Stream parallelStream():返回一个并行流
Stream parallelStream = list.parallelStream();
//创建Stream方式二:通过数组
Object[] object = list.toArray();
//调用Arrays类的static Stream stream(T[] array):返回一个流
Stream
4.3、中间操作
??多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次从全部处理,称为“惰性求值”。
筛选与切片
Stream filter(Predicate<? super T> predicate) //接收Lambda,从流中排除某些元素
Stream distinct() //筛选,通过流所生成元素的hashCode()和equals()去除重复元素
Stream limit(long maxSize) //截断流,使其元素不超过给定数量
Stream skip(long n) //跳过元素,返回一个扔掉前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(long maxSize)互补
import java.util.ArrayList;
import java.util.List;
public class StreamTest {
public static void main(String[] args) {
List list = new ArrayList<>();
list.add(new Person("Sakura",9));
list.add(new Person("Akame",17));
list.add(new Person("Miloto",13));
list.add(new Person("Shana",15));
list.add(new Person("Nanoha",11));
//filter(Predicate<? super T> predicate) //接收Lambda,从流中排除某些元素
list.stream().filter(person -> person.getAge()<=13).forEach(System.out::println);
System.out.println();
//limit(long maxSize) //截断流,使其元素不超过给定数量
list.stream().limit(3).forEach(System.out::println);
System.out.println();
//skip(long n) //跳过元素,返回一个扔掉前n个元素的流。若流中元素不足n个,则返回一个空流。
list.stream().skip(3).forEach(System.out::println);
System.out.println();
//distinct() //筛选,通过流所生成元素的hashCode()和equals()去除重复元素
list.add(new Person("Rimuru",10));
list.add(new Person("Rimuru",10));
list.add(new Person("Rimuru",11));
list.add(new Person("Rimuru",11));
list.add(new Person("Rimuru",11));
list.stream().distinct().forEach(System.out::println);
}
}
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this(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;
}
public String toString(){
return "Person{ name:" + name + ",age:" + age + "}";
}
public boolean equals(Object obj) {
if(obj instanceof Person){
Person person = (Person)obj;
if(name.equals(person.name)){
if(age == person.age){
return true;
}
}
}
return false;
}
public int hashCode() {
return name.hashCode()+age;
}
}
映射
Stream map(Function<? super T,? extends R> mapper) //接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper) //接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream
IntStream mapToInt(ToIntFunction<? super T> mapper) //接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream
LongStream mapToLong(ToLongFunction<? super T> mapper) //接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream
Stream flatMap(Function<? super T,? extends Stream<? extends R>> mapper) //接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有的流连接成一个流
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StreamTest {
public static void main(String[] args) {
List list = Arrays.asList("aa","bb","cc","dd");
Stream> streamStrean = list.stream().map(StreamTest::fromStringToStream);
streamStrean.forEach(s -> s.forEach(System.out::println));
System.out.println();
Stream characterStream = list.stream().flatMap(StreamTest::fromStringToStream);
characterStream.forEach(System.out::println);
}
//将字符串中的多个字符构成的集合转换为对应的Stream的实例
public static Stream fromStringToStream(String str){
ArrayList list = new ArrayList<>();
for (Character character : str.toCharArray()) {
list.add(character);
}
return list.stream();
}
}
排序
Stream sorted() //产生一个新流,其中按自然顺序排序
Stream sorted(Comparator<? super T> comparator) //产生一个新流,其中按比较器顺序排序
import java.util.ArrayList;
import java.util.List;
public class StreamTest {
public static void main(String[] args) {
List list = new ArrayList<>();
list.add(new Person("Sakura",9));
list.add(new Person("Akame",17));
list.add(new Person("Miloto",13));
list.add(new Person("Shana",15));
list.add(new Person("Nanoha",11));
list.stream().sorted().forEach(System.out::println);
System.out.println();
list.stream().sorted((e1,e2) -> Integer.compare(e1.getAge(),e2.getAge())).forEach(System.out::println);
}
}
public class Person implements Comparable{
private String name;
private int age;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this(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;
}
public String toString(){
return "Person{ name:" + name + ",age:" + age + "}";
}
@Override
public int compareTo(Object o) {
if(o instanceof Person){
Person person = (Person)o;
int compare = this.name .compareTo(person.name);
if(compare != 0){
return compare;
} else {
return Integer.compare(this.age, person.age);
}
}
throw new RuntimeException("传入的数据类型不一致!");
}
}
4.4、终止操作
??终止操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是void。流进行终止操作后,不能再次使用。
匹配与查找
boolean allMatch(Predicate<? super T> predicate) //检查是否匹配所有元素
boolean anyMatch(Predicate<? super T> predicate) //检查是否至少匹配一个元素
boolean noneMatch(Predicate<? super T> predicate) //检查是否没有匹配所有元素
Optional findFirst() //返回第一个元素
Optional findAny() //返回当前流中的任意元素
long count() //返回流中元素总数
Optional max(Comparator<? super T> comparator) //返回流中最大值
Optional min(Comparator<? super T> comparator) //返回流中最小值
void forEach(Consumer<? super T> action) //内部迭代
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class StreamTest {
public static void main(String[] args) {
List list = Arrays.asList(7,17,10,9,11,13,15);
boolean allMath = list.stream().allMatch(e -> e<13);
System.out.println(allMath);
boolean anyMath = list.stream().anyMatch(e -> e<=10);
System.out.println(anyMath);
boolean noneMath = list.stream().noneMatch(e -> e==7);
System.out.println(noneMath);
Optional first = list.stream().findFirst();
System.out.println(first);
Optional any = list.parallelStream().findAny();
System.out.println(any);
long count = list.stream().count();
System.out.println(count);
Optional max = list.stream().max(Integer::compare);
System.out.println(max);
Optional min = list.stream().min((e1,e2) -> Integer.compare(e1, e2));
System.out.println(min);
list.stream().forEach(System.out::println);
}
}
规约
Optional reduce(BinaryOperator accumulator) //可以将流中元素反复结合起来,得到一个值,返回Optional
T reduce(T identity, BinaryOperator accumulator) //可以将流中元素反复结合起来,得到一个值,返回T
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class StreamTest {
public static void main(String[] args) {
List number = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
int sum = number.stream().reduce(10,Integer::sum);
System.out.println(sum);
Optional sum1= number.stream().reduce(Integer::sum);
System.out.println(sum1);
}
}
收集
R collect(Collector<? super T,A,R> collector) //将流转换成其它形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
public class StreamTest {
public static void main(String[] args) {
List list1 = Arrays.asList(7,17,10,9,11,13,15);
list1.stream().filter(e -> e<=13).collect(Collectors.toList()).forEach(System.out::println);
System.out.println();
list1.stream().filter(e -> e<=10).collect(Collectors.toList()).forEach(System.out::println);
}
}
五、Optional类
??Optional
public static Optional of(T value) //创建一个Optional实例,t必须非空
public static Optional empty() //创建一个空的Optional实例
public static Optional ofNullable(T value) //t可以为null
public boolean isPresent() //判断是否包含对象
public void ifPresent(Consumer<? super T> action) //如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它
public T get() //如果调用对象包含值,返回该值,否则抛异常
public T orElse(T other) //如果有值则将其返回,否则返回指定的other对象
public T orElseGet(Supplier<? extends T> supplier) //如果有值则将其返回,否则返回由Supplier接口实现提供的对象
public T orElseThrow() //如果有值则将其返回,否则抛出由Supplier接口实现提供的异常
public class OptionalTest {
public static void main(String[] args) {
Boy boy = new Boy();
String grilName = Boy.getGrilName(boy);
System.out.println(grilName);
boy = null;
grilName = Boy.getGrilName(boy);
System.out.println(grilName);
boy = new Boy("Akame", 13, new Gril("Mikoto Misaka", 13));
grilName = Boy.getGrilName(boy);
System.out.println(grilName);
}
}
public class Person{
private String name;
private int age;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this(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;
}
public String toString(){
return "Person{ name:" + name + ",age:" + age + "}";
}
}
import java.util.Optional;
public class Gril extends Person{
private Boy boy;
public Gril(){
}
public Gril(String name){
super(name);
}
public Gril(String name,int age){
super(name, age);
}
public Gril(String name,int age,Boy boy){
super(name, age);
this.boy = boy;
}
public void setBoy(Boy boy){
this.boy = boy;
}
public Boy getBoy(){
return boy;
}
public String toString(){
return "Person{ name:" + getName() + ",age:" + getAge() + "boy:" + boy + "}";
}
public static String getBoyName(Gril gril){
Optional grilOptional = Optional.ofNullable(gril);
//此时gril1一定非空
Gril gril1 = grilOptional.orElse(new Gril("Sakura",9,new Boy("Kikyou",9)));
Boy boy = gril1.getBoy();
Optional griloOptional = Optional.ofNullable(boy);
//此时boy1一定非空
Boy boy1 = griloOptional.orElse(new Boy("Kagome",9));
return boy1.getName();
}
}
import java.util.Optional;
public class Boy extends Person{
private Gril gril;
public Boy(){
}
public Boy(String name){
super(name);
}
public Boy(String name,int age){
super(name, age);
}
public Boy(String name,int age,Gril gril){
super(name, age);
this.gril = gril;
}
public void setGril(Gril gril){
this.gril = gril;
}
public Gril getGril(){
return gril;
}
public String toString(){
return "Person{ name:" + getName() + ",age:" + getAge() + "gril:" + gril + "}";
}
public static String getGrilName(Boy boy){
Optional boyOptional = Optional.ofNullable(boy);
//此时boy1一定非空
Boy boy1 = boyOptional.orElse(new Boy("Rimuru",10,new Gril("Mikoto",10)));
Gril gril = boy1.getGril();
Optional griloOptional = Optional.ofNullable(gril);
//此时gril1一定非空
Gril gril1 = griloOptional.orElse(new Gril("Misaka",10));
return gril1.getName();
}
}
六、语法改进
6.1、try语句升级
import java.io.IOException;
import java.io.InputStreamReader;
public class Template {
public static void main(String[] args) {
//Java 8 中资源关闭操作,可实现资源的自动关闭
//要求自动关闭的资源的初始化必须放在try的一堆小括号中
try(InputStreamReader reader = new InputStreamReader(System.in)){
char[] cbuf = new char[20];
int len;
if((len = reader.read(cbuf)) != -1){
String str = new String(cbuf,0,len);
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}