Lambda: 本质是函数式接口的实例(区别:在Python中lambda本质是函数)
函数式接口: 只有一个抽象方法的接口。 可用@functionalInterface来注解。
代码-内置函数接口Predicate(lambda来作为函数接口的实例)
Predicate<String> pre = x -> x.contains("京")
package com.xj.java;
import org.junit.Test;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;
/**
* @author jia
* @create 2021-12-22 5:31 下午
*/
public class LambdaTest {
@Test
public void Test(){
String[] src = {"北京","成都","天津","南京"};
List<String> res = filter(src,x -> x.contains("京"));
System.out.println(res); // [北京, 南京]
}
public static List<String> filter(String[] src, Predicate<String> pre){
// 内置函数接口-Predicate
LinkedList<String> stringFilter = new LinkedList<>();
for (String s : src){
if (pre.test(s))
stringFilter.add(s);
}
return stringFilter;
}
}
方法引用(MethodRef)
是特殊的lambda表达式。引用已有的实现来替代“函数式接口的实现”,而不用重复实现。 比如下方,Array.sort()中需要传入Comparable接口的实现对象,除了可以传入匿名实现类、和lambda表达式,还可以直接传入已有的接口实现的引用。
String[] stringsArray = {"Hello","World"};
//使用lambda表达式和类型对象的实例方法
Arrays.sort(stringsArray,(s1,s2)->s1.compareToIgnoreCase(s2));
//使用方法引用
//引用的是类型对象的实例方法
Arrays.sort(stringsArray, String::compareToIgnoreCase);
引用自定义的接口实现。
class ComparisonProvider{
public int compareByName(Person a,Person b){
return a.getName().compareTo(b.getName());
}
public int compareByAge(Person a,Person b){
return a.getBirthday().compareTo(b.getBirthday());
}
}
ComparisonProvider provider = new ComparisonProvider();
//使用lambda表达式
//对象的实例方法
Arrays.sort(persons,(a,b)->provider.compareByAge(a,b));
//使用方法引用
//引用的是对象的实例方法
Arrays.sort(persons, provider::compareByAge);
甚至可以引用构造方法
public static <T, SOURCE extends Collection<T>, DEST extends Collection<T>>
DEST transferElements(SOURCE sourceColletions, Supplier<DEST> colltionFactory) {
DEST result = colltionFactory.get();
for (T t : sourceColletions) {
result.add(t);
}
return result;
}
...
final List<Person> personList = Arrays.asList(persons);
//使用lambda表达式
Set<Person> personSet = transferElements(personList,()-> new HashSet<>());
//使用方法引用
//引用的是构造方法
Set<Person> personSet2 = transferElements(personList, HashSet::new);
Stream API: 函数式编程风格、用于操作容器、
Stream代码: 分为3部分介绍,对应了Stream的3个过程,Stream实例化,Stream中间操作,Stream终止操作
package com.xj.java;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author jia
* @create 2021-12-23 3:55 下午
*/
public class StreamTest {
/**
* Stream分为如下3步。
* */
public static Stream<Integer> step1(){
/**
* 0. Stream分为串行流和并行流。
* */
Stream<Integer> stream = Arrays.asList(1, 2, 3).stream(); // 串行流
Stream<Integer> integerStream = Arrays.asList(1, 2, 3).parallelStream(); // 并行流
/**
* 1. Stream实例化 - 4种方式
* */
// 方式1-集合
Stream<Integer> stream1 = Arrays.asList(1, 2, 3,4,5,6,6,6,6).stream();
// 方式2-数组
Stream<Integer> stream2 = Arrays.stream(new Integer[]{1, 2, 3,4,5,6,6,6,6});
// 方式3-Stream.of静态方法
Stream<Integer> Stream3 = Stream.of(1, 2, 3,4,5,6,6,6,6);
// 方式4-迭代器、生成器
Stream<Integer> stream4 = Stream.iterate(0, t -> t + 1).limit(9);
return stream1;
}
public static Stream<Integer> step2(){
/**
* 2. Stream中间操作
* */
// 1. filter(predict函数式接口实例)
Stream<Integer> filter = step1().filter(x -> x.compareTo(2) > 0);
// 2. limit(int)
Stream<Integer> limit = step1().limit(8);
// 3. skip(int)
Stream<Integer> skip = step1().skip(1);
// 4. distinct() 通过hashCode()和equals()来去重。
Stream<Integer> distinct = step1().distinct();
// 5. map(函数式接口实例) 将流中元素照指定函数映射。
Stream<Integer> map = step1().map(x -> x * 10);
// 6. flatMap(函数式接口实例) 将流中元素照指定函数映射。map和flatmap区别见test_map_flatmap测试。
// 7. 排序
Stream<Integer> sorted = step1().sorted((x, y) -> -1 * Integer.compare(x, y));// 无参数则自然排序
return filter;
}
@Test
public void step3(){
/**
* 3.1 Stream终止操作 -- 查找、遍历
* */
boolean bool;
// 1.allMatch --是否全部匹配条件
bool = step2().allMatch(e -> e > 4);
System.out.println(bool);
// 2. noneMatch-- 是否没有匹配的元素
bool = step2().noneMatch(e -> e == 2);
System.out.println(bool);
// 3.findFirst -- 返回首个元素
System.out.println(step2().findFirst());
// 4. findAny -- 返回任意元素
System.out.println(step2().findAny());
// 5. count -- 总数。类型为long
System.out.println(step2().count());
// 6. 比较
System.out.println(step2().max(Integer::compare)); // 或者(x,y) -> Integer.compare(x,y)和(x,y) -> x-y)等
System.out.println(step2().min(Integer::compare));
// 7.foreach 内部迭代
step2().forEach(e -> System.out.print(e + " "));
System.out.println();
// 8. 对比7 外部迭代-使用集合的迭代
Arrays.asList(1,2,3).forEach(e -> System.out.print(e + " "));
System.out.println();
/**
* 3.2 Stream终止操作 -- 归约 reduce 将流中元素反复以xx方式结合起来,得到一个值。
* */
// 3.2.1 计算数字之和
Integer reduce = Arrays.asList(1,2,3).stream().reduce(0, (a,b) -> a + b);// 或者 Integer::sum
System.out.println(reduce);
// 3.2.2 计算数字之积
Integer reduce1 = Arrays.asList(1, 2, 3).stream().reduce(1, (a, b) -> a * b);
System.out.println(reduce);
/**
* 3.3 Stream终止操作 -- 收集 collect 将流中元素以xx方式收集,比如收集到List,Set,Map。
* */
// 3.3.1 - 转为List
List<Integer> collect = Arrays.asList(1, 2, 3).stream().collect(Collectors.toList());
collect.forEach(e -> System.out.print(e + " "));
System.out.println();
// 3.3.2 - 转为Set
Set<Integer> collect1 = Arrays.asList(1, 2, 3).stream().collect(Collectors.toSet());
collect1.forEach(e -> System.out.print(e + " "));
System.out.println();
}
@Test
public void test_map_flatmap(){
/*
比较map和flatmap的区别。
采用同一个映射方法,将容器中的字符串拆分为字符。
flatmap: 流{"good","man"} -> 流{'g','o','o','d','m','a','n'}
map: 流{"good","man"} -> 流{流{'g','o','o','d'},流{'m','a','n'}}
*/
Stream<String> stream = null;
// flatmap
stream = Arrays.asList("good", "man").stream();
Stream<Character> flatmap_characterStream = stream.flatMap(StreamTest::fromString2Stream);
flatmap_characterStream.forEach(x -> System.out.print(x + " "));
System.out.println();
// map
stream = Arrays.asList("good", "man").stream();
Stream<Stream<Character>> map_streamStream = stream.map(StreamTest::fromString2Stream);
map_streamStream.forEach(x -> x.forEach(s -> System.out.print(s + " "))); // 注意区别
}
public static Stream<Character> fromString2Stream(String str){
ArrayList<Character> characters = new ArrayList<>();
for (char c : str.toCharArray()){
characters.add(c);
}
return characters.stream();
}
}
测试step3()
false true Optional[3] Optional[3] 7 Optional[6] Optional[3] 3 4 5 6 6 6 6 1 2 3 6 6 1 2 3 1 2 3
Optional: 避免空指针问题
使用指南
Optional可以避免显式的空值检查,一般使用方式为
T obj = Optional.ofNullable(T t).orElse(T other)
或T obj = Optional.of(T t).get()
。第一种传入参数t允许为空,以备选对象的方式避免空指针的问题,第二种传入参数t不可为空,以抛异常的方式来避免空指针。 第一种方式类似于python的语法:obj = t or other
代码-有无Optional的情况下避免空指针的做法
下面是核心代码
package com.xj.java;
import org.junit.Test;
import java.util.Optional;
/**
* @author jia
* @create 2021-12-23 10:44 下午
*/
public class OptionalTest {
@Test
public void PersonTest(){
// 一个人只有左手。没有Optional时,通过提前判断来避免空指针
Person person = new Person();
person.setLeftHand(new Hand("左"));
if (person.getLeftHand() != null){
person.getLeftHand().holdOut();
person.getLeftHand().drawBack();
} else
System.out.println("没有左手");
if (person.getRightHand() != null){
person.getRightHand().holdOut();
person.getRightHand().drawBack();
}else
System.out.println(" !! 没有右手");
}
@Test
public void OptionalPersonTest(){
// 一个人只有左手。有Optional时,无需使用判断就能避免空指针
OptionalPerson person = new OptionalPerson();
person.setLeftHand(new Hand("左"));
person.getLeftHand().holdOut();
person.getLeftHand().drawBack();
person.getRightHand().holdOut();
person.getRightHand().drawBack();
}
}
class OptionalPerson{
// 一般人有两个手,但也有人没有手。
private Hand leftHand = null;
private Hand rightHand = null;
public OptionalPerson() {
}
public Hand getLeftHand() {
Optional<Hand> handOptional = Optional.ofNullable(this.rightHand);
Hand hand = handOptional.orElse(new Hand("!!Optional-(没有右手)"));
return hand;
}
public void setLeftHand(Hand leftHand) {
this.leftHand = leftHand;
}
public Hand getRightHand() {
Optional<Hand> handOptional = Optional.ofNullable(this.rightHand);
Hand hand = handOptional.orElse(new Hand("!!Optional-(没有左手)"));
return hand;
}
public void setRightHand(Hand rightHand) {
this.rightHand = rightHand;
}
}
class Person{
// 一般人有两个手,但也有人没有手。
private Hand leftHand = null;
private Hand rightHand = null;
public Hand getLeftHand() {
return leftHand;
}
public void setLeftHand(Hand leftHand) {
this.leftHand = leftHand;
}
public Hand getRightHand() {
return rightHand;
}
public void setRightHand(Hand rightHand) {
this.rightHand = rightHand;
}
}
class Hand{
// 这是一个手的3个动作。
public String hand = null;
public Hand(String hand) {
this.hand = hand; // 左或右
}
public void drawBack(){
System.out.println(this.hand + "手收回");
}
public void holdOut() {
System.out.println(this.hand + "手伸出");
}
}