Java8函数式编程学习笔记
Java 8 函数式编程学习笔记
@(JAVASE)[java8, 函数式编程, lambda]
参考内容
Java 8中重要的函数接⼝
接⼝参数返回类型⽰例
Predicate<T>T boolean这张唱⽚已经发⾏了吗Consumer<T>T void输出⼀个值
Function<T,R>T R获得Artist 对象的名字Supplier<T>None T⼯⼚⽅法UnaryOperator<T>T T逻辑⾮(!) BinaryOperator<T>(T, T)T求两个数的乘积(*)
扩展函数接⼝
接⼝参数返回类型⽰例ToLongFunction<T>T long
LongFunction<R>long R
LongUnaryOperator long long
常⽤的流操作
// collect
@Test
public void collectToList() {
List<String> collected = Stream.of("a", "b", "c").List());
assertEquals(Arrays.asList("a", "b", "c"), collected);
}
// map
@Test
public void mapToUpperCase() {
List<String> collected = Stream.of("a", "b", "hello").map(String::toUpperCase).collect(toList());        assertEquals(asList("A", "B", "HELLO"), collected);
}
// filter
@Test
public void functionalStringsWithNumbers() {
List<String> beginningWithNumbers = Stream.of("a", "1abc", "abc1")
.filter(value -> Character.isDigit(value.charAt(0))).List());
assertEquals(Collections.singletonList("1abc"), beginningWithNumbers);
}
// flatMap
@Test
public void flatMapCharacters() {
List<Integer> together = Stream.of(Arrays.asList(1, 2), Arrays.asList(3, 4))
.flatMap(Collection::stream).List());
assertEquals(asList(1, 2, 3, 4), together);
}
// min
@Test
public void streamsMinLength() {
List<Track> tracks = asList(
new Track("Bakai", 524),
new Track("Violets for Your Furs", 378),
new Track("Time Was", 451));
Track shortestTrack = tracks.stream().min(Comparatorparing(Track::getLength)).get();        (1), shortestTrack);
}
// reduce
@Test
public void sumUsingReduce() {
int count = Stream.of(1, 2, 3).reduce(0, (acc, element) -> acc + element);
assertEquals(6, count);
}
@Test
public void expandedReduce() {
BinaryOperator<Integer> accumulator = (acc, element) -> acc + element;
int count = accumulator.apply(accumulator.apply(accumulator.apply(0, 1), 2), 3);
assertEquals(6, count);
}
@Test
public void countUsingReduceFor() {
int acc = 0;
for (Integer element : asList(1, 2, 3)) {
acc = acc + element;
}
assertEquals(6, acc);
}
reduce模式
基本原理
// 初始值
int acc = 0;
for (Integer element : asList(1, 2, 3)) {
// 累加处理+合并处理
acc = acc + element;
}
reduce⽅法API
// accumulator 累加处理
Optional<T> reduce(BinaryOperator<T> accumulator);
// identity 初始值
// accumulator 累加处理
T reduce(T identity, BinaryOperator<T> accumulator);
// identity 初始值
// accumulator 累加处理
// combiner 合并处理
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
案例
使⽤reduce和Lambda表达式实现map
public static <I, O> List<O> map(Stream<I> stream, Function<I, O> mapper) {
duce(new ArrayList<O>(), (acc, x) -> {
List<O> newAcc = new ArrayList<>(acc);
newAcc.add(mapper.apply(x));
return newAcc;
}, (List<O> left, List<O> right) -> {
List<O> newLeft = new ArrayList<>(left);
newLeft.addAll(right);
return newLeft;
});
}
使⽤reduce和Lambda表达式实现filter
public static <I> List<I> filter(Stream<I> stream, Predicate<I> predicate) {
duce(new ArrayList<I>(), (acc, x) -> {
List<I> newAcc = new ArrayList<>(acc);
if (st(x)) {
newAcc.add(x);
}
return newAcc;
}, (List<I> left, List<I> right) -> {
List<I> newLeft = new ArrayList<>(left);
newLeft.addAll(right);
return newLeft;
});
}
类库
基本类型
public long countRunningTime() {
return countFeature(album -> Tracks()
.mapToLong(track -> Length())
.sum());
}
public static void printTrackLengthStatistics(Album album) {
IntSummaryStatistics trackLengthStats = Tracks()
.mapToInt(Track::getLength).summaryStatistics();
System.out.printf("Max: %d, Min: %d, Ave: %f, Sum: %d",
}
重载解析
总结
总⽽⾔之,Lambda表达式作为参数时,其类型由它的⽬标类型推导得出,推导过程遵循如下规则: - 如果只有⼀个可能的⽬标类型,由相应函数接⼝⾥的参数类型推导得出;
- 如果有多个可能的⽬标类型,由最具体的类型推导得出;
- 如果有多个可能的⽬标类型且最具体的类型不明确,则需⼈为指定类型。
PS:三种情况分别对应,⽆重载、有重载且重载参数为⽗⼦关系、有重载且重载参数⽆关联。
情况⼀
private void overloadedMethod(Predicate<Integer> predicate) {
System.out.print("Predicate");
}
@Test
public void mostSpecificPredicate() {
// 输出:IntPredicate
overloadedMethod((x) -> true);
}
情况⼆
private interface IntPredicate extends Predicate<Integer>{
@Override
boolean test(Integer value);
}
private void overloadedMethod(Predicate<Integer> predicate) {
System.out.print("Predicate");
}
private void overloadedMethod(IntPredicate predicate) {
System.out.print("IntPredicate");
}
@Test
public void mostSpecificPredicate() {
// 输出:IntPredicate
overloadedMethod((x) -> true);
}
情况三
private interface IntPredicate {
public boolean test(int value);
}
private void overloadedMethod(Predicate<Integer> predicate) {
System.out.print("Predicate");
}
private void overloadedMethod(IntPredicate predicate) {
System.out.print("IntPredicate");
}
@Test
public void mostSpecificPredicate() {
// 输出:IntPredicate
overloadedMethod((IntPredicate) (x) -> true);
}
默认⽅法
三定律
1. 类胜于接⼝。如果在继承链中有⽅法体或抽象的⽅法声明,那么就可以忽略接⼝中定义的⽅法。
2. ⼦类胜于⽗类。如果⼀个接⼝继承了另⼀个接⼝,且两个接⼝都定义了⼀个默认⽅法,那么⼦类中定义的⽅法胜出。
3. 没有规则三。如果上⾯两条规则不适⽤,⼦类要么需要实现该⽅法,要么将该⽅法声明为抽象⽅法。
其中第⼀条规则是为了让代码向后兼容。
public default void welcome() {
message("Parent: Hi!");
}
Optional
@Test
lambda编程public void examples() {
Optional<String> a = Optional.of("a");
assertEquals("a", a.get());
Optional emptyOptional = pty();
Optional alsoEmpty = Optional.ofNullable(null);
assertFalse(emptyOptional.isPresent());
assertTrue(a.isPresent());
assertEquals("b", Else("b"));
assertEquals("c", ElseGet(() -> "c"));
}
⾼级集合类和收集器
收集器

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。