Java8新特性
接口的默认方法和静态方法
接口中的默认方法
给接口加入一个新方法,意味着所有的实现类都必须为其提供一个实现。那现在这个时候我们就进退两难了:你如何改变已发布的接口而不破坏已有的实现呢?
接口中的默认方法的语法:
-
当子类继承父类或实现接口时,如果父类中的方法名和接口中的默认方法名相同时,父类中的同名方法的优先级高于接口中的同名默认方法。
# 1.父类和接口
class ParentA{ // 父类中的普通方法 public void hello(){ System.out.println("ParentA.hello..."); } } interface IParentB{ // 接口中的默认方法 default void hello(){ System.out.println("default IParentB.hello..."); } }
# 2.子类继承父类或实现接口
// 子类继承父类或实现接口时,如果父类中的普通方法和接口中的默认方法名相同时,父类中的方法优先于接口中的默认方法 public class TestInterface2 extends ParentA implements IParentB { public static void main(String[] args) { TestInterface2 t = new TestInterface2(); t.hello(); } }
控制台输出
-
子接口继承父接口,如果子接口重写父接口中的默认方法时,以子接口为准
package com.tipdm.demo1; public class TestInterface3 implements IParentD { public static void main(String[] args) { TestInterface3 t = new TestInterface3(); t.hello(); } } interface IParentC{ // 接口中的默认方法 default void hello(){ System.out.println("default IParentC.hello..."); } } interface IParentD extends IParentC{ // 接口中的默认方法 // 子接口继承父接口,如果子接口重写父接口中的默认方法时,以子接口为准 @Override default void hello(){ System.out.println("default IParentD.hello..."); } }
控制台效果:
-
子类实现接口时,如果子类重写接口中的默认方法时,以子类为准
package com.tipdm.demo1; public class TestInterface3 implements IParentD { public static void main(String[] args) { TestInterface3 t = new TestInterface3(); t.hello(); } // 子接口继承父接口,如果子接口重写父接口中的默认方法时,以子接口为准 // 子类实现接口时,如果子类重写接口中的默认方法时,以子类为准 @Override public void hello() { System.out.println("TestInterface3.hello"); } } interface IParentC{ // 接口中的默认方法 default void hello(){ System.out.println("default IParentC.hello..."); } } interface IParentD extends IParentC{ // 接口中的默认方法 // 子接口继承父接口,如果子接口重写父接口中的默认方法时,以子接口为准 @Override default void hello(){ System.out.println("default IParentD.hello..."); } }
控制台效果
接口中的静态方法
接口中的默认方法和静态方法的作用
-
默认方法可以提供接口方法的默认实现,从而减少实现类的工作量。
子类可以重写接口中的默认方法。
-
静态方法可以为接口提供与接口相关的工具方法,这些方法可以直接通过接口名来调用,而不需要创建实现类的实例。
子类不能重写接口中的静态方法,只能通过接口名.静态方法名调用。
Lambda表达式
使用Lambda表达式来替代匿名内部类
package com.tipdm.demo2;
import org.junit.Test;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class TestLambda1 {
private List<User> list = Arrays.asList(
new User(1,"张三","男",28,5000.0),
new User(7,"李四","女",25,7000.0),
new User(4,"王五","男",18,9000.0),
new User(2,"赵六","女",23,15000.0),
new User(5,"孙七","男",21,25000.0)
);
// 使用匿名内部类实现排序
@Test
public void test1(){
// 按年龄降序
list.sort(new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
return -Integer.compare(o1.getAge(),o2.getAge());
}
});
for(User user:list){
System.out.println(user);
}
System.out.println("-----------------------------");
// 按工资升序
list.sort(new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
return Double.compare(o1.getSalary(),o2.getSalary());
}
});
for(User user:list){
System.out.println(user);
}
}
// 使用Lambda表达式来替代匿名内部类
@Test
public void test2(){
// 按年龄降序
// list.sort(new Comparator<User>() {
// @Override
// public int compare(User o1, User o2) {
// return -Integer.compare(o1.getAge(),o2.getAge());
// }
// });
list.sort((o1,o2)->-Integer.compare(o1.getAge(),o2.getAge()));
for(User user:list){
System.out.println(user);
}
System.out.println("-----------------------------");
// 按工资升序
list.sort((o1,o2)-> Double.compare(o1.getSalary(),o2.getSalary()));
for(User user:list){
System.out.println(user);
}
}
}
Lambda表达式语法
-
paramaters
:类似方法中的形参列表,这里的参数是函数式接口里抽象方法的参数。这里的参数类型可以明确的声明,也可不声明而由JVM
隐含的推断。另外当只有一个推断类型时可以省略掉圆括号。 -
->:操作符:有些语言也把其称之为箭头函数,注意:操作符的符号不能分开写。
-
**方法体:**可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不反回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不反回。
注意:
paramaters
:
Lambda表达式的参数列表的类型和个数要与函数式接口中的抽象方法的参数列表的类型和个数相同
Lambda表达式的返回值的类型和函数式接口中的抽象方法的返回值类型相同
接口中的抽象方法定义
- 使用Lambda表达式
Lambda表达式基础语法格式
package com.tipdm.demo2;
import org.junit.Test;
import java.util.Comparator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* Lambda表达式,是函数式接口中的抽象方法的实现
* 接口中的抽象方法的定义
*
* Lambda表达式的基础语法格式:
* 1) 格式一:无参,无返回值
* 2) 格式二:无参,有返回值
* 3) 格式三:有1个参数,无返回值
* 4) 格式四:有1个参数,有返回值
* 5) 格式五:有2个以上参数,有返回值,且方法体中有多条语句
* 6) 格式六:在Lambda方法体中只有一条语句,return和大括号可以省略不写
* 7) 格式七:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以进行自动推断类型
*/
public class TestLambda3 {
// 1) 格式一:无参,无返回值
@Test
public void test1(){
// 使用匿名内部类
Runnable rn1 = new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
};
rn1.run();
// 使用Lambda表达式
Runnable rn2 = ()-> System.out.println("hello");
}
// 2) 格式二:无参,有返回值
@Test
public void test2(){
// 使用匿名内部类
Supplier<Integer> supplier1 = new Supplier<Integer>() {
@Override
public Integer get() {
return 2;
}
};
Integer num1 = supplier1.get();
System.out.println(num1);
// 使用Lambda表达式
Supplier<Integer> supplier2 = ()-> 2;
Integer num2 = supplier2.get();
System.out.println(num2);
}
// 3) 格式三:有1个参数,无返回值
@Test
public void test3(){
// 使用匿名内部类
Consumer<String> consumer1 = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println("hello "+s);
}
};
consumer1.accept("泰迪教育科技");
// 使用Lambda表达式
Consumer<String> consumer2 = (s)-> System.out.println("hello "+s);
consumer2.accept("泰迪教育科技");
}
// 4) 格式四:有1个参数,有返回值
@Test
public void test4(){
// 使用匿名内部类
Function<Double,String> fun1 = new Function<Double, String>() {
@Override
public String apply(Double aDouble) {
return aDouble+"";
}
};
String result1 = fun1.apply(200.0);
System.out.println(result1);
// 使用Lambda表达式
Function<Double,String> fun2 = (o1)-> o1+"";
String result2 = fun2.apply(200d);
System.out.println(result2);
}
// 5) 格式五:有2个以上参数,有返回值,且方法体中有多条语句,必须显示使用return关键字
@Test
public void test5(){
// 使用匿名内部类
Comparator<Integer> comparator1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
int result1 = comparator1.compare(10, 20);
System.out.println(result1);
// 使用Lambda表达式
Comparator<Integer> comparator2 = (o1,o2)->{
System.out.println("lambda表达式");
return Integer.compare(o1,o2);
};
int result2 = comparator2.compare(10, 20);
System.out.println(result2);
}
// 6) 格式六:在Lambda方法体中只有一条语句,return和大括号可以省略不写
@Test
public void test6(){
// 使用匿名内部类
Comparator<Integer> comparator1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
int result1 = comparator1.compare(10, 20);
System.out.println(result1);
// 使用Lambda表达式
// Comparator<Integer> comparator2 = (o1,o2)->{return Integer.compare(o1,o2);};
Comparator<Integer> comparator3 = (o1,o2)->Integer.compare(o1,o2);
int result2 = comparator3.compare(10, 20);
System.out.println(result2);
}
// 7) 格式七:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以进行自动推断类型
@Test
public void test7(){
Comparator<Integer> comparator3 = (Integer o1, Integer o2)->Integer.compare(o1,o2);
int result2 = comparator3.compare(10, 20);
System.out.println(result2);
}
}
函数式接口
在什么地方使用函数式接口
在函数式接口上使用Lambda表达式
什么是函数式接口
-
“函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。
-
Jdk1.8提供了一个@FunctionalInterface注解来定义函数式接口,如果我们定义的接口不符合函数式的规范便会报错。
自定义函数式接口
-
函数式接口中只能包含一个抽象方法。
-
如果在接口上添加了@FunctionalInterface,强制编译器检查接口中只能有一个抽象方法。
- 接口中如果只有一个抽象方法,该接口是函数式接口。
- 接口中如果有1个以上抽象方法,该接口不是函数式接口,同时编译器报错。
-
如果在接口上没有添加@FuncationalInterface,编译器不检查接口中有几个抽象方法。
- 接口中如果只有一个抽象方法,该接口是函数式接口。
- 接口中如果有1个以上的抽象方法时,该接口不是函数式接口,且编译器不会报错。
# 1.函数式接口
package com.tipdm.demo1;
@FunctionalInterface
public interface INumberOper<T> {
/**
* 数字相关的一些操作
* @param t1 操作数1
* @param t2 操作数2
* @return
*/
T calc(T t1,T t2);
// void print1();
}
# 2.测试类
package com.tipdm.demo1;
import org.junit.Test;
// 自定义函数式接口
public class TestLambda4 {
@Test
public void test1(){
// 数字相关的一些操作
// 加法
INumberOper<Integer> oper1 = (o1,o2) -> o1+o2;
Integer result1 = oper1.calc(10, 20);
System.out.println(result1);
// 乘法
INumberOper<Integer> oper2 = (t1,t2) -> t1*t2;
Integer result2 = oper2.calc(10, 20);
System.out.println(result2);
}
}
内置函数式接口
java8之前提供的内置函数式接口
java8提供的四大核心内置函数式接口
package com.tipdm.demo2;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* java8的四大核心的内置函数式接口
* 1) 消费型接口:Consumer<T>
* void accept(T t)
* 2) 供给型接口:Supplier<T>
* T get()
* 3) 函数型接口:Function<T,R>
* R apply(T t)
* 4) 断言型接口:Predicate<T>
* boolean test(T t)
*/
public class TestLambda5 {
/**
1) 消费型接口:Consumer<T>
void accept(T t)
*/
@Test
public void test1(){
Consumer<String> consumer = (name) -> System.out.println("hello "+name);
consumer.accept("泰迪教育科技");
}
/**
* 2) 供给型接口:Supplier<T>
* T get()
*/
@Test
public void test2(){
// 获取用户的对象实例
Supplier<User> supplier = ()->new User();
User user = supplier.get();
System.out.println(user);
System.out.println("----------------");
// 随机生成彩票号码
List<Integer> list = generatorRandomNum(6, () -> ((int) (Math.random() * 10)) + 1);
System.out.println(list);
}
/*
3.随机生成彩票号码
1)创建List集合用于保存随机生成的彩票号码
2)随机生成1-10之间的整数,将生成出来的整数与集合中的数据进行比较,判断是否重复,如果重复就重新生成,如果不重复就保存到集合中
3)共生成6个随机的整数
*/
private List<Integer> generatorRandomNum(int nums, Supplier<Integer> supplier){
List<Integer> list = new ArrayList<>();
// 1、遍历生成几个(nums)的随机数
for(int i=0;i<nums;i++){
// 2、获取随机数
Integer rn = supplier.get();
// 3、将随机数添加到集合中
list.add(rn);
}
return list;
}
/*
3) 函数型接口:Function<T,R>
* R apply(T t)
*/
@Test
public void test3(){
// 功能:将字符串转换为全小写
Function<String,String> function1 = (str)->str.toLowerCase();
String result = function1.apply("ABCD");
System.out.println(result);
// 功能:获取字符串的长度
Function<String,Integer> function2 = (str)->str.length();
Integer length = function2.apply("abcde");
System.out.println(length);
}
/**
* 4) 断言型接口:Predicate<T>
* boolean test(T t)
*/
@Test
public void test4(){
List<User> userList = Arrays.asList(
new User("张三",28,"男"),
new User("李四",18,"女"),
new User("王五",25,"男"),
new User("赵六",23,"女"),
new User("孙七",21,"男")
);
// 条件:查询年龄在25岁以上的用户
List<User> ageUserList = queryUserByCondition(userList, (user) -> user.getAge() >= 25);
System.out.println(ageUserList);
System.out.println("-------------------");
// 条件:查询性别为男的用户信息
List<User> genderUserList = queryUserByCondition(userList, (user) -> user.getGender().equals("男"));
System.out.println(genderUserList);
}
// 根据条件过滤用户数据
private List<User> queryUserByCondition(List<User> userList, Predicate<User> predicate){
List<User> list = new ArrayList<>();
for(User user:userList){
if(predicate.test(user)){
list.add(user);
}
}
return list;
}
}
java8提供的扩展内置函数式接口
方法引用和构造引用
方法引用
-
方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。
-
方法引用提供了一种引用而不执行的方式,它需要由兼容的函数式接口来构成目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。
-
当Lambda表达式中只是执行一个方法调用时,不用Lambda表达式,直接通过方法引用的形式可读性更高一些。方法引用是一种更简洁易懂的Lambda表达式。
注意:方法引用是一个Lambda表达式,其中方法引用的操作符是双冒号==“::”==。
语法格式:
-
对象::实例方法名。
-
类名::静态方法名。
-
类名::实例方法名。
package com.tipdm.demo1;
import org.junit.Test;
import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* 方法引用
* 语法:
* 1) 对象::实例方法名
* 2) 类名::静态方法名
* 3) 类名::实例方法名
*
* 构造引用:
* 语法:
* 类名::new
*
* 数组引用
* 语法:
* 数据类型[]::new
*/
public class Test1 {
// 1) 对象::实例方法名
@Test
public void test1(){
// Consumer<String> consumer = (name) -> System.out.println(name);
// 1.1) 示例1
PrintStream out = System.out;
// lambda表达式写法
Consumer<String> consumer1 = (name) -> out.println(name);
// 方法引用的写法
Consumer<String> consumer2 = out::println;
consumer2.accept("泰迪教育");
System.out.println("---------------");
// 1.2) 示例2
User user = new User("张三", "男", 28);
// 使用lambda表达式
Supplier<Integer> supplier1 = ()->user.getAge();
// 使用方法引用
Supplier<Integer> supplier2 = user::getAge;
Integer age = supplier2.get();
System.out.println(age);
}
// 2) 类名::静态方法名
@Test
public void test2(){
// 使用lambda表达式
Comparator<Integer> comparator1 = (o1,o2)->Integer.compare(o1,o2);
int compare1 = comparator1.compare(10, 20);
System.out.println(compare1);
// 使用方法引用
Comparator<Integer> comparator2 = Integer::compare;
int compare2 = comparator2.compare(10, 20);
System.out.println(compare2);
}
// 3) 类名::实例方法名
/*
使用类::实例方法名时使用函数式接口中的抽象方法,抽象方法的第1个参数作为实例方法的调用者
即是抽象方法的第1个参数是对应类的一个对象
当前这种语法是【对象::实例方法名】语法的一种变相写法
*/
@Test
public void test3(){
// 使用lambda表达式
Comparator<Integer> comparator1 = (o1,o2)->o1.compareTo(o2);
// 使用方法引用
Comparator<Integer> comparator2 = Integer::compareTo;
int compare = comparator2.compare(10, 20);
System.out.println(compare);
}
}
构造引用
语法:
-
类名::new
–》需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致
package com.tipdm.demo1;
import org.junit.Test;
import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
public class Test1 {
// 构造引用
// 语法:类名::new
@Test
public void test4(){
// 1) 无参的构造
// lambda表达式
Supplier<User> supplier1 = ()->new User();
// 构造引用
Supplier<User> supplier2 = User::new;
User user1 = supplier2.get();
System.out.println(user1);
System.out.println("--------------");
// 2) 1参的构造
// lambda表达式
Function<String,User> function1 = (name)->new User(name);
// 构造引用
Function<String,User> function2 = User::new;
User user2 = function2.apply("张三");
System.out.println(user2);
System.out.println("---------------");
// 3) 2参的构造
// lambda表达式
BiFunction<String,Integer,User> function3 = (name,age)->new User(name,age);
// 构造引用
BiFunction<String,Integer,User> function4 = User::new;
User user3 = function4.apply("张三", 28);
System.out.println(user3);
}
}
数组引用
语法:
- 数据类型[]::new
package com.tipdm.demo1;
import org.junit.Test;
import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
public class Test1 {
// 数组引用
// 语法:数据类型[]::new
@Test
public void test5(){
// 数组的初始化
// lambda表达式
Function<Integer,int[]> function1 = (length)->new int[length];
// 数组引用
Function<Integer,int[]> function2 = int[]::new;
int[] array = function2.apply(5); // 数组的长度为5
System.out.println(array.length);
}
}
Stream API
Stream的创建
-
通过Collection接口的默认方法stream()创建
List<Good> list = new ArrayList(); Stream<Good> stream = list.stream();
-
通过Stream接口的静态方法of()创建
Student stu = new Student(); Stream<Student> stuStream = Stream.of(stu);
-
通过Arrays类的静态方法stream()创建
String[] strs ={"aa","bb"}; Stream<String> stream = Arrays.stream(strs);
Stream的中间操作
1.过滤和切片
- filter():根据指定的条件过滤出满足条件的元素。
- limit():限制元素的数量。
- skip():跳过指定数量的元素。
- distinct():去除重复的元素。
package com.tipdm.demo1;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class Test1 {
List<Good> goodList = Arrays.asList(
new Good("g0001","礼京果觅阳光玫瑰晴王葡萄","葡萄",38.9,500,"斤","云南","礼京果觅"),
new Good("g0002","黄桃水果礼盒","黄桃",36.5,100,"斤","山东","桃小安"),
new Good("g0003","自然故事广西百色贵妃芒果","芒果",19.9,300,"斤","广西","自然故事(ZIRANGUSHI)"),
new Good("g2001","京鲜生桂味荔枝","荔枝",13.3,100,"斤","广东","京鲜生"),
new Good("g2002","京豆云预定漳州新鲜杨桃2","杨桃",8.9,200,"斤","福建","京豆云"),
new Good("g2003","京豆云预定漳州新鲜杨桃3","杨桃",9.9,200,"斤","福建","京豆云"),
new Good("g0001","礼京果觅阳光玫瑰晴王葡萄1","葡萄",37.9,500,"斤","云南","礼京果觅"),
new Good("g0004","礼京果觅阳光玫瑰晴王葡萄2","葡萄",36.9,500,"斤","云南","礼京果觅"),
new Good("g0005","礼京果觅阳光玫瑰晴王葡萄3","葡萄",35.9,500,"斤","云南","礼京果觅"),
new Good("g0006","礼京果觅阳光玫瑰晴王葡萄","葡萄",34.9,500,"斤","云南","礼京果觅"),
new Good("g0007","礼京果觅阳光玫瑰晴王葡萄","葡萄",33.9,500,"斤","云南","礼京果觅")
);
/**
中间操作:
过滤和切片
1) filter():根据指定的条件过滤出满足条件的元素。
2) limit():限制元素的数量。
3) skip():跳过指定数量的元素。
4) distinct():去除重复的元素。
*/
@Test
public void test1(){
// 获取Stream流对象的方式
// Stream<Good> stream = goodList.stream();
// 1) filter():根据指定的条件过滤出满足条件的元素。
// 中间操作
Stream<Good> typeStream = goodList.stream()
.filter(good -> good.getType().equals("葡萄"));
// 终止操作
typeStream.forEach(System.out::println);
System.out.println("-------------------------");
// 2) limit():限制元素的数量。
// 中间操作
Stream<Good> typeStream2 = goodList.stream()
.filter(good -> good.getType().equals("葡萄"))
.limit(3);
// 终止操作
typeStream2.forEach(System.out::println);
System.out.println("-------------------------");
// 3) skip():跳过指定数量的元素。
goodList.stream()
.filter(good -> good.getType().equals("葡萄"))
.skip(2)
.forEach(System.out::println);
System.out.println("-------------------------");
// 5) distinct():去除重复的元素。(重写hashCode和equals方法)
List<Good> list1 = goodList.stream()
.distinct()
.collect(Collectors.toList());
list1.forEach(System.out::println);
System.out.println("-------------------------");
}
}
2.排序
@Test
public void test1(){
// 4) sorted():排序
goodList.stream()
.filter(good -> good.getType().equals("葡萄"))
.sorted((g1,g2)->Double.compare(g1.getPrice(),g2.getPrice()))
.forEach(System.out::println);
System.out.println("-------------------------");
}
3.映射
- map:对每个元素进行映射操作,将其转换为另一种类型。接收一个函数作为参数,该参数会应用到每个元素上,并将其映射其一个新的元素。
@Test
public void test2(){
// 1) map:对每个元素进行映射操作,将其转换为另一种类型。接收一个函数作为参数,该参数会应用到每个元素上,并将其映射其一个新的元素。
// 1) 初始化对象
// 正常数据
City city = new City(1,"广州");
Country country = new Country(10,"中国",city);
Student student = new Student(20,"张三",28,country);
// 非正常数据
Student student2 = new Student(30,"李四",20,null);
// 功能:想要获取学生所在城市名称
// student.getCountry().getCity().getCityName();// ok
// student2.getCountry().getCity().getCityName(); // 会抛出NullPointException异常
String cityName1 = getCityName1(student);
String cityName2 = getCityName2(student);
System.out.println("传统方式获取的城市名称:"+cityName1);
System.out.println("java8的Stream API的方式获取的城市名称:"+cityName2);
// 学生姓名
String stuName = Stream.of(student)
.map(Student::getSname).findFirst().get();
System.out.println("学生名称:"+stuName);
}
// 功能:想要获取学生所在城市名称
// 传统方式
public String getCityName1(Student stu){
if(stu!=null){
Country country = stu.getCountry();
if(country!=null){
City city = country.getCity();
if(city!=null){
return city.getCityName();
}
}
}
return null;
}
// 功能:想要获取学生所在城市名称
// java8的Stream API的方式
public String getCityName2(Student stu){
Stream<Student> stuStream = Stream.of(stu);
Stream<String> stringStream = Stream.of(stu)
.map(Student::getCountry)
.map(Country::getCity)
.map(City::getCityName);
Optional<String> firstOptional = stringStream.findFirst();
return firstOptional.orElse(null);
}
Stream的终止操作
1.匹配与查找
allMatch()
:是否匹配(都符合)所有元素anyMatch()
:是否匹配至少一个元素noneMatch()
:是否没有匹配(都不符合)所有元素findFirst()
:返回第一个元素findAny()
:返回当前流中的任意元素max()
:返回流中的最大值min()
:返回流中的最小值count()
:返回流中元素的总个数
2.收集
Collectors.toList()
:收集流中的数据到集合(List)中Collectors.toSet()
:收集流中的数据到集合(Set)中Collectors.counting()
:总记录数Collectors.maxBy()
:最大值Collectors.groupingBy()
:根据某一条件分组