引用
https://www.liaoxuefeng.com/wiki/1252599548343744/1305207799545890
https://www.cnblogs.com/SIHAIloveYAN/p/11288064.html
https://www.liaoxuefeng.com/wiki/1252599548343744/1322402873081889
Stream API
Stream 是一种惰性运算
- Stream输出的元素可能并没有预先存储在内存中,而是实时计算出来的,故而可以打印”无限“的数
Stream<BigInteger> naturals = createNaturalStream(); // 不计算,无限数流,先不考虑实现
Stream<BigInteger> s2 = naturals.map(BigInteger::multiply); // 不计算
Stream<BigInteger> s3 = s2.limit(100); // 不计算
s3.forEach(System.out::println); // 计算
可以看到,一个Stream转换为另一个Stream时,实际上只存储了转换规则,并没有任何计算发生。
中间操作与终止操作
- 中间操作是懒执行,即直到实际需要处理结果(终止操作)时才会执行,常见的有
filter()
map()
flatMap()
distinct()
sorted()
peek()
limit()
skip()
- 终止操作可以遍历流生成结果或直接消费。终止操作执行后,可以认为管道流被消费了并不能再被使用。
forEach()
forEachOrdered()
toArray()
reduce()
collect()
min()
max()
count()
anyMatch()
allMatch()
noneMatch()
findFirst()
findAny()
lambda表达式和方法引用
lambda
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)
lambda表达式可以直接用在,只定义单方法的接口(FunctionalInterface功能接口)上,方法使用@FunctionalInterface注释,从注释中得知单方法定义。
- 从概念上讲,功能接口仅具有一种抽象方法。 由于默认方法具有实现,因此它们不是抽象的。 如果接口声明了一个覆盖java.lang.Object的公共方法之一的抽象方法,则该方法也不计入接口的抽象方法计数,因为该接口的任何实现都将具有java.lang.Object或其他地方的实现。
编译器自动识别出传入参数(s1,s2)的类型和返回值类型,免去了复杂的匿名类实现
Arrays.sort(array, (s1, s2) -> {
return s1.compareTo(s2);
});
原实现
Arrays.sort(array, new Comparator<String>() {
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
方法引用
方法引用只要当某个方法签名和接口恰好一致(方法参数一致,返回类型相同),就可以直接把方法名作lombda表达式传入
String[] array = new String[] { "Apple", "Orange", "Banana", "Lemon" };
Arrays.sort(array, Main::cmp);
Arrays.sort(array, String::compareTo);
List<Person> persons = array.stream().map(Person::new).collect(Collectors.toList());
static int cmp(String s1, String s2) {
return s1.compareTo(s2);
}
可以传入静态方法,实例方法,构造方法
- 静态方法,正常传递
Arrays.sort(array, Main::cmp);
- 实例方法,实例类型被看做第一个参数类型
Arrays.sort(array, String::compareTo);
public final class String {
public int compareTo(String o) {
...
}
}
因为实例方法有一个隐含的this参数,String类的compareTo()方法在实际调用的时候,第一个隐含参数总是传入this
相当于静态方法:
public static int compareTo(this, String o);
- 传入构造方法时,实例类型被看做返回类型
- 构造方法
class Person {
String name;
public Person(String name) {
this.name = name;
}
}
- 使用
List<String> names = List.of("Bob", "Alice", "Tim");
List<Person> persons = new ArrayList<>();
for (String name : names) {
persons.add(new Person(name));
}
lambda 作返回值
如果一个方法的返回值类型是一个函数式接口,那么就可以直接返回一个Lambda表达式
- 创建
public static Comparator<String> getComparator(){
//方法的返回值类型是一个接口,那么我们可以返回这个接口的匿名内部类
/*return new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//按照字符串的降序排序
return o2.length()-o1.length();
}
};*/
return (String o1, String o2)-> o2.length() - o1.length();
}
- 使用
public static void main(String[] args) {
//创建一个字符串数组
String [] array={"aaa","bbbb","cc","ddd"};
//调用Arrays中的sort方法,对字符串数组进行排序
Arrays.sort(array,getComparator());
}
通过function包使用lambda
了解了lambda表达式与方法引用后,就可以来了解java.util.function包
接口 描述
Predicate//谓词,断言 接收一个传入参数,返回一个boolean
Function<T,R>//功能 接受一个输入参数,返回一个结果
Supplier//供给 无参数,返回一个结果
Consumer//消费 接受一个输入参数,并且不返回任何结果
BiFunction<T,U,R> 接受两个输入参数的方法,并且返回一个结果
BiConsumer<T,U>
接受两个输入参数的操作,并且不返回任何结果
其实就是普通的接口,通过实现,lambda等方式实现后,根据签名一致性,像普通实例一样调用。
一次谓词使用经历,依赖querydsl
- dsl中有一个BooleanExpression,他是一个实现了Predicate的抽象类,表示boolean表达式。
public abstract class BooleanExpression extends LiteralExpression<Boolean> implements Predicate
- 我编写了一个单一方法返回booleanExpression的接口类QuerySpec,通过QuerySpec来限定谓词使用范围(只被某个扩展于BaseEntity的实体使用,学习时可以不用)。
public interface QuerySpec<T extends BaseEntity> extends Serializable {
long serialVersionUID = 1L;
BooleanExpression toExpression();
static <T extends BaseEntity> QuerySpec<T> not(QuerySpec<T> spec) {
return spec != null ? () -> {
return spec.toExpression().not();
} : null;
}
default QuerySpec<T> and(QuerySpec<T> other) {
return () -> {
return this.toExpression().and(other.toExpression());
};
}
default QuerySpec<T> or(QuerySpec<T> other) {
return () -> {
return this.toExpression().or(other.toExpression());
};
}
}
- 一个用来组合条件返回booleanExpression的通用抽象类SpecHelper
public abstract class SpecHelper {
/**
* 返回一个 参数在指定某个collection内的 布尔表达式
*/
static <T> BooleanExpression parameterIn(SimpleExpression<T> parameter, Collection<T> collection) {
if (collection == null) {
return alwaysTrue;
}
return parameter.in(collection);
}
/**
* 返回一个 参数等于指定right值 布尔表达式
*/
static <T> BooleanExpression parameterEq(SimpleExpression<T> parameter, T right) {
if (right == null) {
return alwaysTrue;
}
return parameter.eq(right);
}
}
- 规约TestSpec
public abstract class TestSpec {
public static QuerySpec<LeakPoint> dataAuth() {
...
}
public static QuerySpec<Test> testType(TestType testType) {
return () -> parameterEq(QTest.test.testType, testType);
}
}
......
- 使用
QuerySpec<Test> spec = TestSpec.dataAuth();
if (filter != null) {
spec = spec.and(TestSpec.range(filter.getRange()))
.and(TestSpec.Ids(filter.getIds()))
.and(TestSpec.testType(filter.getTestType()))
}
通过使用谓词,将多个条件组合起来,在条件为空时不进行筛选,不为空的时候进行筛选,以实现自定义查询。