Lambda 表达式(lambda expression)是一个匿名函数,简化我们调用匿名函数的过程
@Test
public void test1() {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类执行");
}
};
r1.run();
Runnable r2 = () -> System.out.println("lambda语法执行!");
r2.run();
}
从上面可以看出,真正执行的只有这么一句话有用,但是为了实现匿名内部内,必须写这么多无用代码
(x,y) -> {} lambda 表达式分为左边和右边,中间用一个 ->连接起来 ,左边代表的是需要传入抽象方法的入参,右边为抽象方法的实现
1. 在接口中只能够允许有一个抽象方法
2. 在函数接口中定义object类中方法
3. 使用默认或者静态方法
4. @FunctionalInterface 表示该接口为函数接口
Java中使用Lambda表达式的规范,必须是为函数接口
java 系统内置函数
消费型接口:
Conusmer
void accept(T t);
BiConusmer
void accept(T t,U u);//增加一种入参类型
供给型接口:
Supplier
void get()
函数型接口
Function
R apply(T t);
UnaryOperator
T apply(T t);//入参与返回值类型一致
BiFunction
R apply(T t,U u);//增加一个参数类型
BinaryOperator
T apply(T t1,T t2);//l两个相同类型入参与同类型返回值
ToIntFunction //限定返回int
ToLongFunction//限定返回long
ToDoubleFunction//限定返回double
IntFunction//限定入参int,返回泛型R
LongFunction//限定入参long,返回泛型R
DoubleFunction//限定入参double,返回泛型R
断言型接口
Predicate
boolean test(T t);
() // 参数列表
-> // 连接符
{} // 方法体
/**
* .........................................
* . Getting rid of the fetters of fame .
* . one can concentrate on his technique .
* . .......................................
*
* @Author: LQ
* @Date: 20 Feb 2023 21:47
* @DAY_NAME_FULL: Monday
* @Description:
* 一、lambda 表达式基础语法:引入新的操作符 -> 该操作符称为箭头操作符 或 lambda 操作符
* 箭头操作符将lambda 表达式拆分为两部分
*
* 左侧:lambda 表达式参数列表
* 右侧: lambda 表达式所需执行的功能,即lambda 体
*
* 语法一:无参数,无返回值
* () -> {System.out.println("hello lambda ")}
*
* 语法格式二:有一个参数,无返回值
* (e) -> {System.out.println(e)}
*
* 若只有一个参数,小括号可以不写
* e -> {System.out.println(e)}
*
* 语法三:有两个参数,有返回值,并且lambda 体中有多条语句
* (x,y) -> return x
* Comparator com = (x,y) ->{
* System.out.println("lambda 函数式接口");
* return Integer.compare(x,y);
* };
* 若lambda 体中只有一条语句,大括号和return 可以省略
*
*
* 左右遇单括号省
*
*
* 二:lambda 表达式需要 函数式接口 支持
* 函数式接口:接口中只有一个实现抽象方法 可以用注解 @FunctionInterface 来检查接口
*/
public class TestLambda2 {
// 需求对一个数进行运算
@Test
public void test4() {
Integer operator = operator(10, x -> x * 10);
System.out.println(operator);
Integer operator1 = operator(10, x -> x + 10);
System.out.println(operator1);
}
public Integer operator(Integer num,MyFun myFun) {
return myFun.getValue(num);
}
@Test
public void test3() {
Comparator com = (x,y) ->{
System.out.println("lambda 函数式接口");
return Integer.compare(x,y);
};
Comparator com1 = (x,y) ->Integer.compare(x,y);
Comparator com2 = Integer::compare;
}
@Test
public void test1() {
// 默认还是final
int num = 0;
Runnable ru = new Runnable() {
@Override
public void run() {
System.out.println("hello world " + num);
}
};
ru.run();
System.out.println("===============");
Runnable ru1 = () -> System.out.print("hello lambda "+ num);
ru1.run();
}
@Test
public void test2() {
Consumer con = (x) -> System.out.print(x);
con.accept("奉眠武力高升");
Consumer con1 = x -> System.out.print(x);
con1.accept("奉眠武力高升");
}
* Consumer 消费型接口
* void accept(T t)
* Supplier 供给型接口
* T get();
* Function(T,R) 函数型接口
* R apply(T t)
*
* Predication 断言型接口
* boolean test(T t)
*
*
*/
public class TestLambda3 {
// predicate 断言型接口
@Test
public void test4() {
List list = Arrays.asList("张三","李四","王五","赵六","田七");
List list1 = predicateHandler(list, (str) -> str.length() > 3);
list1.forEach(System.out::println);
}
// 将满足条件的字符串放入到集合中
public List predicateHandler(List list, Predicate pre) {
List resList = new ArrayList<>();
for (String str : list) {
if (pre.test(str)) {
resList.add(str);
}
}
return resList;
}
// function 函数式接口 传进一个值,返回另外一个值
@Test
public void test3() {
Integer functionHandler = functionHandler("小白鞋", (str) -> str.length());
System.out.println(functionHandler);
}
// 用于处理字符串,返回字符串长度
public Integer functionHandler(String str, Function fun) {
return fun.apply(str);
}
// 供给型接口
// Supplier
@Test
public void test2() {
List integerList = supplierHandler(10,() -> (int) (Math.random() * 100));
integerList.forEach(System.out::println);
}
// 产生多少个数到集合中去
public List supplierHandler(int num, Supplier sup) {
List list = new ArrayList<>(num);
for (int i = 0;i < num; i ++) {
Integer n = sup.get();
list.add(n);
}
return list;
}
// consumer 接口
@Test
public void test1() {
consumerHandler(1000,(x) -> System.out.println("公司聚餐花费:"+x));
}
public void consumerHandler(double money, Consumer cn){
cn.accept(money);
}
* 一、方法引用
* 若 lambda 体中的内容有方法已经实现,我们可以使用方法引用
* lambda 表达式另外一种表达形式
*
* 三种语法格式
* 方法传入的参数与返回的参数要保持一致
* 1、lambda 体中调用方法的参数列表与返回值类型,
* 要与函数式接口中的抽象方法函数的列表和返回值类型保持一致
* 2、若 lambda 参数列表中第一参数是实列方法的调用者,而第二个参数是实列方法的参数是,可以使用className::method
* 对象::实列方法名
*
* 类::静态方法名
*
* 类:: 实列方法名(注意事项)
*
*
* 二、构造器引用
* 格式:
* className::new
* 注意:需要调用的构造器参数列表要与函数式接口抽象方法参数列表保持一致
*
*
* 三、数组引用
* Type:new
*/
public class TestMethodRef {
// 数组引用
@Test
public void test7() {
Function fu1 = (l) -> new String[l];
String[] arr1 = fu1.apply(10);
System.out.println(arr1.length);
Function fu2 = String[]::new;
String[] arr2 = fu2.apply(10);
System.out.println(arr2.length);
}
// 构造器
@Test
public void test6() {
Function fun = (x) -> new Employee(x);
Employee e1 = fun.apply(16);
System.out.println(e1);
Function fn1 = Employee::new;
Employee e2 = fn1.apply(22);
System.out.println(e2);
BiFunction fn2 = (x,y) -> new Employee(x,y);
BiFunction fn3 = Employee::new;
Employee employee = fn3.apply("张天翼", 24);
System.out.println(employee);
}
@Test
public void test5() {
Supplier spu = () -> new Employee();
// 构造器引用
Supplier spu1 = Employee::new;
Employee employee = spu1.get();
System.out.println(employee);
}
// 类::实列方法
@Test
public void test4() {
BiPredicate bp = (s1,s2) -> s1.equals(s2);
boolean result1 = bp.test("张三", "李四");
System.out.println(result1);
BiPredicate bp1 = String::equals;
boolean result2 = bp.test("张三","张三");
System.out.println(result2);
}
// 类::静态方法名
@Test
public void test3() {
Comparator com = (x,y) -> Integer.compare(x,y);
// 方法引用,静态方法
Comparator com1 = Integer::compare;
Set set = new TreeSet<>(com1);
set.add(5);
set.add(1);
set.add(3);
set.add(2);
set.add(4);
set.forEach(System.out::println);
}
@Test
public void test1() {
Consumer com = (x) -> System.out.println(x);
com.accept("2023年2月21");
// 方法引用
PrintStream ps = System.out;
Consumer com1 = ps::println;
com1.accept("2023年2月21");
Consumer com2 = System.out::println;
com2.accept("2023年2月21");
}
@Test
public void test2() {
Employee employee = new Employee();
employee.setName("奉眠");
employee.setAge(33);
Supplier sup = () -> employee.getName();
String name = sup.get();
System.out.println(name);
// 方法引用 对象::方法名
Supplier sup1 = employee::getAge;
Integer age = sup1.get();
System.out.println(age);
}
}
什么是stream 流 :是数据渠道,用于操作数据源(集合、数组等) 所生成的元素序列。“集合讲的是数据,流讲的是算!”
注意:
1、Stream自己不会存储元素
2、Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
3、Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
stream使用步骤
1、创建stream:一个数据源(如集合,数组),获取到一个流
2、中间操作:一个中间操作链,对数据源的数据进行处理
3、终止操作(终端操作):执行中间操作链,并产品结果
// 创建stream
@Test
public void test1() {
// 1、通过Collection 系列集合提供的是太热爱 或者 paraselStream
List list = new ArrayList<>();
Stream stream1 = list.stream();
// 2、通过arrays 中的静态方法 stream() 获取数组流
Employee[] employees = new Employee[10];
Stream stream2 = Arrays.stream(employees);
// 3、通过stream 类中的静态方法 of()
Stream stream3 = Stream.of("aa", "hello", "good");
// 4、创建无限流 迭代 从0 开始一直迭代
Stream.iterate(0,(x) -> x + 2)
.limit(10)
.forEach(System.out::println);
// 生成
Stream.generate(() -> Math.random())
.limit(5)
.forEach(System.out::println);
}
* @Description: 中间操作
*
* 筛选与切片
* filter - 接收 lambda ,从流中排除某些元素
* limit - 截断流,使其元素不超过给定数量
* skip(n) 跳过元素,返回一个丢弃到前面的n个元素流,若元素不足n个,则返回一个空流,与limit(n)互补
* distinct - 筛选,通过流所生成的元素的hashcode 和 equals 去掉重复元素
*
*
* 多个中间操作可以链接起来形成一个流水线,除非流水线出发终止操作,否则中间操作不会执行
* 任何处理,而在终止操作是一次性全部处理,称为 惰性求值
*/
public class TestStreamApi2 {
List employees = Arrays.asList(
new Employee("唐三",18,8888.21)
,new Employee("小舞",18,7778.11)
,new Employee("宁蓉蓉",16,9999.22)
,new Employee("奉眠",23,18888.21)
,new Employee("屋南",66,68888.66)
,new Employee("敖无虚",55,48888.66)
,new Employee("敖无虚",55,48888.66)
);
// 排序
// sorted --自然排序 Comparable
// sorted(comparator) - 定制排序
@Test
public void test7() {
List list = Arrays.asList("eeee", "bbb", "ccc", "ddd","aaaa");
// 自然排序
list.stream()
.sorted()
.forEach(System.out::println);
System.out.println("-----------------");
// 定制排序
employees.stream()
.sorted((o1,o2) -> {
if (o1.getAge() == o2.getAge()) {
return o1.getName().compareTo(o2.getName());
}
return Integer.compare(o1.getAge(),o2.getAge());
})
.forEach(System.out::println);
}
/**
* 映射
* map - 接受lambda ,将元素转换为其他形式或提取信息。接受一个函数作为参数,
* 该函数会被应用到每个元素上,并将其映射成一个新的元素
* flatMap 接受一个函数作为参数,将流中的每个值都换成另外一个流,然后把所有的流连接成一个流
*
*/
@Test
public void test6() {
List list = Arrays.asList("aaa", "bbb", "ccc", "ddd");
list.stream()
//.map(String::toUpperCase)
.map((str) -> str.toUpperCase())
.forEach(System.out::println);
System.out.println("----------------");
employees.stream()
.map(Employee::getName)
.forEach(System.out::println);
System.out.println("----------------");
Stream> streamStream = list.stream()
.map(TestStreamApi2::filterCharacter);
System.out.println("----------------");
streamStream.forEach(
(stream) ->
stream.forEach(System.out::println)
);
System.out.println("----------------");
list.stream()
.flatMap(TestStreamApi2::filterCharacter)
.forEach(System.out::println);
}
public static Stream filterCharacter(String str) {
List list = new ArrayList<>();
for (Character ch : str.toCharArray()) {
list.add(ch);
}
return list.stream();
}
// 出重 distinct 需要重写 equals 和hashcode 方法
@Test
public void test5(){
employees.stream()
.filter((e) -> e.getSalary() > 8888)
.distinct()
.forEach(System.out::println);
}
@Test
public void test4() {
employees.stream()
.filter((employee -> employee.getSalary() > 7777))
.skip(2)
.forEach(System.out::println);
}
// limit
@Test
public void test3() {
employees.stream()
.filter((e) -> {
System.out.println("短路");
return e.getSalary() > 7777;
})
.limit(2)
.forEach(System.out::println);
}
// 内部迭代,迭代操作由 stream api 完成
@Test
public void test1() {
Stream stream = employees.stream()
.filter(e -> {
System.out.println("stream api 中间操作");
return e.getAge() > 18;
});
// 终止操作,一次性执行全部内容, 惰性求值
stream.forEach(System.out::println);
}
// 外部迭代
@Test
public void test2() {
Iterator iterator = employees.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
/**
* 查找与匹配
* allMatch - 检查是否匹配所有元素
* anyMatch - 检查是否至少匹配一个元素
* noneMatch - 检查是否没有匹配所有元素
* findFirst - 返回第一个元素
* findAny - 返回当前流中任意元素
* count - 返回六中元素的总个数
* max - 返回流中最大值
* min - 返回流中最小值
*/
@Test
public void test1() {
boolean b = employees.stream()
//.filter((e) -> e.getStatus().equals(EmployeeExt.Status.BUSY))
.allMatch((e) -> e.getStatus().equals(EmployeeExt.Status.BUSY));
System.out.println(b);
boolean b1 = employees.stream()
.anyMatch((e) -> e.getStatus().equals(EmployeeExt.Status.BUSY));
System.out.println(b1);
boolean b2 = employees.stream()
.noneMatch((e) -> e.getStatus().equals(EmployeeExt.Status.BUSY));
System.out.println(b2);
Optional optional = employees.stream()
.sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
.findFirst();
System.out.println(optional.get());
Optional optional1 = employees.stream()
.filter((e) -> e.getStatus().equals(EmployeeExt.Status.FREE))
.findAny();
System.out.println(optional1.get());
}
// 执行结果:
false
true
false
EmployeeExt(name=奉眠, age=23, salary=18888.21, status=BUSY)
EmployeeExt(name=屋南, age=66, salary=68888.66, status=FREE)
@Test
public void test2() {
long count = employees.stream()
.count();
System.out.println(count);
Optional optional = employees.stream()
.max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(optional.get());
Optional optional2 = employees.stream()
.map(EmployeeExt::getSalary)
.min(Double::compare);
System.out.println(optional2.get());
}
// 执行结果:
5
EmployeeExt(name=澜风, age=100, salary=2248888.66, status=VOCATION)
18888.21
/**
* 规约 reduce BinaryOperator accumulator 可以将流中元素反复结合 map reduce
*/
@Test
public void test3() {
List list = Arrays.asList(100, 20, 30, 50, 1000);
Integer sum = list.stream()
.reduce(0, (x, y) -> x + y);
Integer sum1 = list.stream()
.reduce(0, Integer::sum);
System.out.println(sum);
System.out.println(sum1);
Optional optional = employees.stream()
.map(EmployeeExt::getSalary)
.reduce((x, y) -> Double.sum(x, y));
System.out.println(optional.get());
}
// 执行结果:
1200
1200
4634442.85
收集
/**
* 收集
* collect - 将流转换为其他形式,接受一个Collector 接口的实现,用于给stream 元素做汇总
* Collectors
* collector 接口中方法实现决定了如何对流执行收集操作(如 收集 List
* Set , Map )。 但是 collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例
*
*/
@Test
public void test4() {
// 将名字收集添加到一个新集合中
List listNames = employees.stream()
.map(EmployeeExt::getName)
.collect(Collectors.toList());
listNames.forEach(System.out::println);
System.out.println("--------");
Set setNames = employees.stream()
.map(EmployeeExt::getName)
.collect(Collectors.toSet());
setNames.forEach(System.out::println);
System.out.println("--------");
HashSet hs = employees.stream()
.map(EmployeeExt::getName)
.collect(Collectors.toCollection(HashSet::new));
hs.stream().forEach(System.out::println);
}
// 执行结果:
奉眠
屋南
敖无虚
澜风
澜风
--------
屋南
敖无虚
奉眠
澜风
--------
屋南
敖无虚
奉眠
澜风
/**
* 收集
*/
@Test
public void test5() {
// 总数
long count = employees.stream()
.collect(Collectors.counting());
System.out.println(count);
System.out.println("---------------------");
//平均值
double ave = employees.stream()
.collect(Collectors.averagingDouble(EmployeeExt::getSalary));
System.out.println(ave);
// 最大值
Optional optional1 = employees.stream()
.collect(Collectors.maxBy((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary())));
System.out.println(optional1.get());
// 最小值
Optional optional2 = employees.stream()
.collect(Collectors.minBy((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary())));
System.out.println(optional2.get());
Optional minD = employees.stream()
.map(EmployeeExt::getSalary)
.collect(Collectors.minBy(Double::compareTo));
System.out.println(minD.get());
}
// 收集
@Test
public void test8() {
DoubleSummaryStatistics dss = employees.stream()
.collect(Collectors.summarizingDouble(EmployeeExt::getSalary));
System.out.println(dss.getMax());
System.out.println(dss.getCount());
System.out.println(dss.getSum());
}
// 结果:
2248888.66
5
4634442.85
分组
@Test
public void test6() {
Map> map = employees.stream()
.collect(Collectors.groupingBy((e) -> e.getStatus()));
System.out.println(map);
Map> map1 = employees.stream()
.collect(Collectors.groupingBy(EmployeeExt::getStatus));
System.out.println(map1);
}
// 结果
{VOCATION=[EmployeeExt(name=澜风, age=100, salary=2248888.66, status=VOCATION), EmployeeExt(name=澜风, age=1001, salary=2248888.66, status=VOCATION)], FREE=[EmployeeExt(name=屋南, age=66, salary=68888.66, status=FREE)], BUSY=[EmployeeExt(name=奉眠, age=23, salary=18888.21, status=BUSY), EmployeeExt(name=敖无虚, age=55, salary=48888.66, status=BUSY)]}
{VOCATION=[EmployeeExt(name=澜风, age=100, salary=2248888.66, status=VOCATION), EmployeeExt(name=澜风, age=1001, salary=2248888.66, status=VOCATION)], FREE=[EmployeeExt(name=屋南, age=66, salary=68888.66, status=FREE)], BUSY=[EmployeeExt(name=奉眠, age=23, salary=18888.21, status=BUSY), EmployeeExt(name=敖无虚, age=55, salary=48888.66, status=BUSY)]}
// 多级分组
@Test
public void test7() {
Map>> map = employees.stream()
.collect(Collectors.groupingBy(EmployeeExt::getStatus,Collectors.groupingBy((e) -> {
EmployeeExt ext = (EmployeeExt) e;
if (ext.getAge() < 30) {
return "青年";
}
if (ext.getAge() < 100) {
return "中年";
}
return "老顽固";
})));
System.out.println(map);
}
// 执行结果
{BUSY={青年=[EmployeeExt(name=奉眠, age=23, salary=18888.21, status=BUSY)], 中年=[EmployeeExt(name=敖无虚, age=55, salary=48888.66, status=BUSY)]}, VOCATION={老顽固=[EmployeeExt(name=澜风, age=100, salary=2248888.66, status=VOCATION), EmployeeExt(name=澜风, age=1001, salary=2248888.66, status=VOCATION)]}, FREE={中年=[EmployeeExt(name=屋南, age=66, salary=68888.66, status=FREE)]}}
Java8 中加入了对时区的支持,带时区的时间为分别为:ZonedDate、ZonedTime、ZonedDateTime其中每个时区都对应着ID,地区ID都为“[区域]/城市)”的格式例如:Asia/Shanghai等
Zoneld: 该类中包含了所有的时区信息
getAvailableZonelds():可以获取所有时区时区信息of(id):用指定的时区信息获取 Zoneld 对象
LocalDate、LocalTime、 LocalDateTime
LocalDate、LocalTime、LocalDateTime 类的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息。
/**
* LocalDate LocalTime LocalDateTime
*/
@Test
public void test1() {
LocalDateTime now = LocalDateTime.now();
System.out.println(now);//2023-02-23T22:21:09.454
// - 1 天
LocalDateTime ldt1 = now.minusDays(1);
System.out.println(ldt1);//2023-02-22T22:21:09.454
// +1 天
LocalDateTime ldt2 = now.plusDays(1);
System.out.println(ldt2);//2023-02-24T22:21:09.454
System.out.println(now.getYear());//2023
System.out.println(now.getMonthValue());//2
System.out.println(now.getDayOfMonth());//23
System.out.println(now.getHour());//22
System.out.println(now.getMinute());//21
System.out.println(now.getSecond());//9
System.out.println(LocalDate.now());//2023-02-23
System.out.println(LocalTime.now());//22:21:09.455
}
时间戳(以 unix 元年:1970年1月1日00:00:00 到某个时间之间的毫秒值
@Test
public void test2() {
Instant ist = Instant.now();
System.out.println(ist);//2023-02-23T14:25:21.209Z
OffsetDateTime offsetDateTime = ist.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime);//2023-02-23T22:25:21.209+08:00
System.out.println(ist.getNano());//209000000
// 元年 + 1秒
Instant instant = Instant.ofEpochSecond(1);
System.out.println(instant);//1970-01-01T00:00:01Z
}
duration: 计算两个 时间之间的间隔
Period: 计算两个 日期之间的间隔
@Test
public void test3() throws Exception {
Instant ist1 = Instant.now();
Thread.sleep(1000);
Instant inst2 = Instant.now();
Duration du1 = Duration.between(ist1,inst2);
System.out.println("间隔:"+du1.toMillis());//1006
LocalDate localDate = LocalDate.of(2022,1,22);
LocalDate ld2 = LocalDate.now();
Period per = Period.between(localDate,ld2);
System.out.println(per.getYears());//1
System.out.println(per.getMonths());//1
System.out.println(per.getDays());//1
}
Optional类(java.util.Optional) 是一个容器类,代表一个值存在或不存在原来用 nul1 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常
/**
* Optional 容器类的常用方法:
* Optional.of(T t) : 创建一个 Optional 实例
* Optional.empty() : 创建一个空的 Optional 实例
* Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
* isPresent() : 判断是否包含值
* orElse(T t) : 如果调用对象包含值,返回该值,否则返回 t
* orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
* map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional,empty()
* flatMap(Function mapper):与 map 类似,要求返回值必须是Optional
*/
// orElse 如果调用对象包含值,返回该值,否则返回 t
@Test
public void test1() {
Optional optional = Optional.of(new EmployeeExt("周世才",55,80000, EmployeeExt.Status.BUSY));
System.out.println(optional.get());
// 结果:EmployeeExt(name=周世才, age=55, salary=80000.0, status=BUSY)
EmployeeExt employee = optional.orElse(new EmployeeExt());
System.out.println(employee);
// 结果:EmployeeExt(name=周世才, age=55, salary=80000.0, status=BUSY)
Optional optional2 = optional.ofNullable(new EmployeeExt());
System.out.println(optional2.get());
// 结果:EmployeeExt(name=null, age=0, salary=0.0, status=null)
// Optional optional2 = Optional.of(null);
// System.out.println(optional2.get());
}
//isPresent() 判断是否包含值
@Test
public void test2() {
Optional optional = Optional.empty();
if (optional.isPresent()) {
System.out.println(optional.get());
}
// Optional optional2 = optional.ofNullable(new EmployeeExt());
// System.out.println(optional2.get());
EmployeeExt employee = optional.orElse(new EmployeeExt());
System.out.println(employee);
}
// 结果:EmployeeExt(name=null, age=0, salary=0.0, status=null)
//orElseGet() :如果调用对象包含值,返回该值,否则返回 s 获取的值
@Test
public void test3() {
Optional optional = Optional.of(new EmployeeExt("周世才",55,80000, EmployeeExt.Status.BUSY));
EmployeeExt ext = optional.orElseGet(EmployeeExt::new);
System.out.println(ext);
//EmployeeExt(name=周世才, age=55, salary=80000.0, status=BUSY)
}
flatMap (Function mapper):与 map 类似,要求返回值必须是Optional
返回一个Optional 对象,使用 Optional.of()
@Test
public void test4() {
Optional optional = Optional.ofNullable((new EmployeeExt("周世才",55,80000, EmployeeExt.Status.BUSY)));
//Optional optional = Optional.of(new EmployeeExt());
Optional optional1 = optional.map(EmployeeExt::getName);
System.out.println(optional1.get());//周世才
Optional optional2 = optional.flatMap((e) -> Optional.of(new EmployeeExt()));
System.out.println(optional2.get());
//EmployeeExt(name=null, age=0, salary=0.0, status=null)
}
java8中增加了default 方法,如果一个接口中与一个类中有相同的方法名称,那么实现类调用的时候已那个为准呢?
// 接口定义default 方法
public interface Fun1 {
default String getName() {
return "我是fun1的getName方法";
}
static void showName() {
System.out.println("我是fun接口showName方法");
}
}
// 类中定义 getName()方法
public class MyClass {
public String getName() {
return "我是MyClass的getName方法";
}
}
// 实现
public class SubClass extends MyClass implements Fun1 {
}
// 测试
public static void main(String[] args) {
SubClass subClass = new SubClass();
System.out.println(subClass.getName());
subClass.getName();
Fun2.showName();
}
猜猜看,是 class中的方法优先还是接口中的方法优先呢?
执行结果:我是MyClass的getName方法
问题2:再定义一个接口fun2 同样的抽象方法,那么这个时候那个优先呢
public class SubClass /*extends MyClass*/ implements Fun1,Fun2 {
@Override
public String getName() {
return Fun2.super.getName();
}
}
结果,编译不通过,必须重写getName()方法,否则编译不过
总结:
接口默认方法的”类优先”原则
1、若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时选择父类中的方法。如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。
2、接口冲突。如果一个接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法 (不管方法是否是默认方法),那么必须覆盖该方法来解决冲突