函数式接口
Predicate
java.util.function.Predicate
@FunctionalInterface
public interface Predicate<T> {
// 函数式接口,布尔返回值
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
Consumer
java.util.function.Consumer
@FunctionalInterface
public interface Consumer<T> {
// 函数式接口,无返回值
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
Funcion
java.util.function.Function
@FunctionalInterface
public interface Function<T, R> {
// 函数式接口,接受 T 为参数,返回 R
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
Supplier
java.util.function.Supplier
@FunctionalInterface
public interface Supplier<T> {
// 函数式接口,返回 T,无参数
T get();
}
同时为简单的数据类型准备了对应的函数式接口,一般是在 Predicate
加上对应的前缀,比如 double
对应的 Predicate
接口为 DoublePredicate
,
复合 Lambda 表达式
比较器
Compartor<Person> c = Comparator.comparing(Person::getName);
逆序
List<Apple> inventory = new ArrayList<>();
inventory.sort(comparing(Apple::getWeight).reversed());
比较器链
thenComparing ,如果对象的第一个 Compartor
比较之后是一样的,就使用第二个 Compartor
List<Apple> inventory = new ArrayList<>();
inventory.sort(comparing(Apple::getWeight).reversed().thenComparing(Apple::getCountry));
谓词复合
-
negate
表示非
-
and
表示与
-
or
表示或
优先级的确定,从左向右。
函数复合
-
compose
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); }
示例代码
Function<Integer, Integer> f = x -> x + 1; Function<Integer, Integer> g = x -> x * 2; Function<Integer, Integer> h = f.compose(g); int result = h.apply(1);
运算方式:f(g(x)) = x * 2 + 1 = 1 * 2 + 1 = 3
-
andThen
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); }
示例代码:
Function<Integer, Integer> f = x -> x + 1; Function<Integer, Integer> g = x -> x * 2; Function<Integer, Integer> h = f.andThen(g); int result = h.apply(1);
运算方式:g(f(x)) = (x * 1) * 2 = (1 + 1) * 2 = 4
compose
和andThen
都返回Function
对象,可以将其进行复合。
流(Stream)
java.util.stream.Stream
定义:从支持数据处理操作的源生成的元素序列
流的特点
-
只能遍历一次
流只能遍历一次,遍历之后,这个流就被消费掉了,不能再次使用。
-
内部迭代
使用
map
之类的方式进行迭代,而不是for-each
等循环方式
流操作
流操作可以分为两大类,中间操作和终端操作。
-
中间操作
中间操作会返回另一个流,让多个流组成一条流水线,如果没有触发终端操作,流不会执行。
-
终端操作
终端操作会从流水线上生成结果,其结果不再是注的值。
流的使用
在使用流的时候,整个链是:
数据源 -> 中间操作 -> 终端操作
使用流
filter
distinct
limit
skip
map
-
flatMap
与 map 的区别,会进行打散操作
sorted
anyMatch : 有一个匹配
allMatch : 全部匹配
noneMatch : 不匹配
findFirst : 第一个
findAny : 查找任意一个
reduce(归约)
T reduce(T identity, BinaryOperator<T> accumulator);
Optional<T> reduce(BinaryOperator<T> accumulator);
<U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner);
流的装箱
boxed 方法可以装一个基本类型的流装箱成包装类型的流
IntStream intStream = menu.stream().mapToInt(Person::getAge);
Stream<Integer> stream = intStream.boxed(); // 装箱
构建流
由值创建流
Stream<String> steam = Stream.of("this is a Steam");
steam.map(String::toUpperCase).forEach(System.out::println);
使用 Stream
的表态方法 of
来创建流。
由数组创建流
int[] arrays = {1, 2, 3, 4, 5, 6};
IntStream stream = Arrays.stream(arrays);
stream.map(x -> x * x).forEach(System.out::println);
文件生成流
try(Stream<String> lines = Files.lines(Paths.get("/Users/mac/Documents/work/demo/loadbalancesuccess.zip"))) {
lines.map(String::isEmpty)
.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
生成无限流
iterate
Stream.iterate(0, n -> n + 2)
.limit(10)
.forEach(System.out::println);
generate
Stream.generate(Math::random)
.limit(5)
.forEach(System.out::println);
iterate 与 generate 的区别:
iterate 方法接受一个初始值,依次应用在每个产生新值上的 Lambda
generate 不是依次对每个新生成的值应用函数
数据收集
收集器(Collector)
java.util.stream.Collectors
静态导入其所有方法
counting
maxBy
minBy
summingInt
summingLong
summingDouble
sumWithCompensation
averagingInt
averagingLong
averagingDouble
joining
toList
toSet
toCollection
toMap
toConcurrentMap
分组 (group)
- groupingBy
- groupingByConcurrent
- collectingAndThen
分区
- partitioningBy
Collector 接口
为 Collector
接口提供自己的实现
// 结果容器
Supplier<A> supplier();
// 计算
BiConsumer<A, T> accumulator();
// 对结果进行合并
BinaryOperator<A> combiner();
// 最终转换
Function<A, R> finisher();
// 返回一个 Characteristics 集合,定义了收集器的行为
Set<Characteristics> characteristics();
Characteristics
-
CONCURRENT
accumulator 函数可以从多个线程同时调用,且该收集器可以并行归约流。
-
UNORDERED
归约结果不受流中项目的遍历和累积顺序的影响
-
IDENTITY_FINISH
方法返回的函数是一个恒等函数,可以跳过。这种情况下,累加器对象将会直接用作归约过程的最终结果
并行处理
第七章
日志调试
peek
Optional
创建 Optional 对象
-
创建一个空的 optional 对象
Optional<String> empty = Optional.empty();
-
依据一个非空值创建 Optional
Optional<String> obj = Optional.of("this is Optional Object");
-
可接受 null 的 Optional
String str = null; Optional<String> optionalStr = Optional.ofNullable(str);
使用 map 从 Optional 对象中撮和转换值
String str = null;
Optional<String> optionalStr = Optional.ofNullable(str);
Optional<Integer> integer = optionalStr.map(String::length);
Integer integer1 = integer.get();
System.out.println(integer1);
使用 flatMap 链接 Optional 对象
使用 map 操作后,如果返回的对象本身是 Optional 包装的,那么就会组成 Option<Option<?>> ,需要使用 flatMap 打散。
Optional 对象的默认行为
- get()
- orElse(T other)
- orElseGet(Supplier<? extends T)
- orElseThrow(Supplier<? extends X> exceptionSupplier)
- ifPresent(Consumer<? super T)
方法 | 描述 |
---|---|
empty | 返回一个空的 Optional 实例 |
filter | 如果值存在并且满足提供的谓词,就返回饮食该值的 Optional 对象,否则返回一个空的 Optional 对象 |
flatMap | 如果人才辈出存在,就对该值提供的 mapping 函数调用,返回一个 Optional 类型的值,否则就返回一个空的 Optional 对象 |
get | 如果该值存在,将该值用 Optional 封装返回,否则抛出一个 NoSuchElementException 异常 |
ifPresent | 如果值存在,就执行使用该值的谅调用,否则什么也不做 |
map | 如果值存在,就对该值执行提供的 mapping 函数调用 |
of | 将指定值用 Optional 封装之后返回,如果该值为 null,则抛出一个 NullPointerCeption 异常 |
ofNullable | 将指定什表 Optional 封装之后返回,如果该值为 null,则返回一个空的 Optional 对象 |
orElse | 如果有值则将其返回,否则返回一个默认值 |
orElseGet | 如果有值则将返回,否则返回一个由指定的 Supplier 接口生成的值 |
orElseThrow | 如果有值则将其返回,否则抛出一个由指定的 Supplier 接口生成的异常 |
CompletableFuture
创建 CompletableFuture 对象
public Future<Double> getPriceAsync(String product) {
CompletableFuture<Double> futurePrice = new CompletableFuture<>();
new Thread(() -> { //创建CompletableFuture对象,它会包含计算的结果
double price = calculatePrice(product); //在另一个线程中以异步方式执行计算
futurePrice.complete(price); //需长时间计算的任务结束并得出结果时,设置Future的返回值
}).start();
return futurePrice; //←─无需等待还没结束的计算,直接返回Future对象
}
异常处理,使用 completeExceptionally
方法将异常从线程中传递出来
public Future<Double> getPriceAsync(String product) {
CompletableFuture<Double> futurePrice = new CompletableFuture<>();
new Thread( () -> { //←─创建CompletableFuture对象,它会包含计算的结果
try {
double price = calculatePrice(product); //←─在另一个线程中以异步方式执行计算
futurePrice.complete(price); //←─需长时间计算的任务结束并得出结果时,设置Future的返回值
} catch (Exception e) {
futurePrice.completeExceptionally(e);
}
}).start();
return futurePrice; //←─无需等待还没结束的计算,直接返回Future对象
}
使用内置的静态方法(工厂方法)
public Future<Double> getPriceAsync1(String product) {
return CompletableFuture.supplyAsync(() -> calculatePrice(product));
}
整合两个 CompletableFuture
CompletableFuture<Double> futurePriceInUSD =
CompletableFuture.supplyAsync(() -> shop.getPrice(product))
.thenCombine(CompletableFuture.supplyAsync(
() -> ExchangeService.getRate(Money.EUR, Money.USD)),
(price, rate) -> price * rate
);
- thenCombine
- thenCombineAsync
新的时间和日期 API
LocalDate、LocalTime
使用 of
方法创建实例,静态不可变对象
LocalDateTime
合并了 LocalDate 和 LocalTime
Instant 时间戳
Duration 、 Period
方法名 | 是否静态方法 | 方法描述 |
---|---|---|
between | 是 | 创建两个时间点之间的 interval |
from | 是 | 由一个临时时间点创建interval |
of | 是 | 由它的组成部分创建 interval 的实例 |
parse | 是 | 由字符串创建 interval 的实例 |
addTo | 否 | 创建该 interval 的副本,并将其叠加到某个指定的 temporal 对象 |
get | 否 | 读取该 interval 的状态 |
isNegative | 否 | 检查该 interval 是否为负值,不包含零 |
isZero | 否 | 检查该 interval 的时长是否为零 |
miuns | 否 | 通过减去一定的时间创建该 interval 的副 |
multipliedBy | 否 | 将 interval 的值乘以某个标量创建该 interval 的副本 |
negated | 否 | 以忽略某个时长的方式去创建该 interval 的副本 |
plus | 否 | 以增加某个指定的时长的方式创建该 interval 的副本 |
subtractFrom | 否 | 从指定的 termporal 对象中减去该 interval |
操纵、解析和格式化日期
方法名 | 是否是静态方法 | 描述 |
---|---|---|
from | 是 | 依据传入的 Temporal 对象创建对象实例 |
now | 是 | 依据系统时钟创建 Temporal 对象 |
of | 是 | 由 Temporal 对象的某个部分创建该对象的实例 |
parse | 是 | 由字符串创建 Temporal 对象的实例 |
atOffset | 否 | 由字符串创建 Temporal 对象的实例 |
atZone | 否 | 将 Temporal 对象和某个时区相结合 |
format | 否 | 使用某个指定的格式器,将 Temporal 对象转换成为字符串 |
get | 否 | 读取 Temporal 对象的某一部分的值 |
minus | 否 | 创建 Temporal 对象的一个副本,通过将当前 Temporal 对象的值减去一定的时长创建该副本 |
plus | 否 | 创建 Temporal 对象的一个副本,通过将当前 Temporal 对象的值加上一定的时长创建该副本 |
with | 否 | 以该 Temporal 对象为模板,对某些状态进行修改创建该对象的副本 |
TemporalAdjuster
进行更加复杂的操作,可以使用重载版本的 with 方法传递一个更多定制化的 TemporalAdjuster 对象。
方法名 | 描述 |
---|---|
dayOfWeekInmonth | 创建一个新的日期,它的值为同一个月中每一周的第几天 |
firstDayOfMonth | 创建一个新的日期,它的值为当月的第一天 |
firstDayOfNextMonth | 创建一个新的日期,它的值为下月的第一天 |
firstDayOfNextYear | 创建一个新的日期,它的值为明年的第一天 |
firstDayOfYear | 创建一个新的日期,它的值为当年的第一天 |
firstInMonth | 创建一个新的日期,它的值为同一个月中,第一个符合星期几要求的值 |
lastDayOfMonth | 创建一个新的日期,它的值为下月的最后一天 |
lastDayOfNextMonth | 创建一个新的日期,它的值为下月的最后一天 |
lastDayofNextYear | 创建一个新的日期,它的值为明年的最后一天 |
lastDayOfYear | 创建一个新的日期,它的值为今年的最后一天 |
lastInMonth | 创建一个新的日期,它的值为同一个月中,最后一个符合星期几要求的值 |
next/previous | 创建一个新的日期,并将其设定为日期调整后或者调整前,前一个符合指定星期几要求的日期 |
nextOrSame/previousOrSame | 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期,如果该日期已经符合要求,直接返回该对象 |
以上 JDK 提供的仍然无法满足要求,可以创建自己的 TemporalAdjuster
@FunctionalInterface
public interface TemporalAdjuster {
Temporal adjustInto(Temporal temporal);
}
实现 TemporalAdjuster
接口,然后在 adjustInto 方法中实现自己的逻辑。
自定义的 TemporalAdjuster 实现
public void testTemporalAdjuster() {
LocalDateTime now = LocalDateTime.now();
LocalDateTime nextYear = now.with((t) -> t.plus(1, ChronoUnit.YEARS));
String format = now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
System.out.println(format);
String format1 = nextYear.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
System.err.println(format1);
}
功能:获取下一年的日期时间对象。
DateTimeFormatter
- 静态常量,预定义的格式
- ofPattern 指定格式