java.util.function.Predicatejava
@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);
}
}
复制代码
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); };
}
}
复制代码
java.util.function.Functionapp
@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;
}
}
复制代码
java.util.function.Supplierdom
@FunctionalInterface
public interface Supplier<T> {
// 函数式接口,返回 T,无参数
T get();
}
复制代码
同时为简单的数据类型准备了对应的函数式接口,通常是在 Predicate
加上对应的前缀,好比 double
对应的 Predicate
接口为 DoublePredicate
,异步
Compartor<Person> c = Comparator.comparing(Person::getName);
复制代码
其内部代码调用的是 compareTo
方法ide
List<Apple> inventory = new ArrayList<>();
inventory.sort(comparing(Apple::getWeight).reversed());
复制代码
@Test
public void testT() {
List<Integer> list = Arrays.asList(3, 2, 1, 2, 2, 2, 5, 6, 7, 5, 4, 9, 100);
list.stream()
.sorted(Comparator.reverseOrder())
.forEach(System.err::println);
}
复制代码
调用 Comparator
的 reverseOrder()
方法能够直接进行天然排序函数
thenComparing ,若是对象的第一个 Compartor
比较以后是同样的,就使用第二个 Compartor
ui
List<Apple> inventory = new ArrayList<>();
inventory.sort(comparing(Apple::getWeight).reversed().thenComparing(Apple::getCountry));
复制代码
negatethis
表示非spa
and
表示与
or
表示或
优先级的肯定,从左向右。
Predicate<B.Name> predicate = (B.Name n) -> "a".equals(name.getName());
Predicate<B.Name> and = predicate.and((n) -> n.getName().endsWith("b"));
复制代码
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
对象,能够将其进行复合。
java.util.stream.Stream
定义:从支持数据处理操做的源生成的元素序列
只能遍历一次(只能消费一次)
流只能遍历一次,遍历以后,这个流就被消费掉了,不能再次使用。
内部迭代
使用 map
之类的方式进行迭代,而不是for-each
等循环方式
错误的示例
String str = "this is successful";
Stream<String[]> stream = Stream.of(str)
.map(s -> s.split(" "));
stream.forEach(System.out::println);
stream.forEach(System.out::println);
复制代码
流操做能够分为两大类,中间操做和终端操做。
中间操做
中间操做会返回另外一个流,让多个流组成一条流水线,若是没有触发终端操做,流不会执行。
终端操做
终端操做会从流水线上生成结果,其结果再也不是注的值。
在使用流的时候,整个链是:
数据源 -> 中间操做 -> 终端操做
filter
distinct
limit
skip
map
flatMap
与 map 的区别,会进行打散操做
sorted
anyMatch : 有一个匹配
allMatch : 所有匹配
noneMatch : 不匹配
findFirst : 第一个
findAny : 查找任意一个
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();
}
复制代码
Stream.iterate(0, n -> n + 2)
.limit(10)
.forEach(System.out::println);
复制代码
Stream.generate(Math::random)
.limit(5)
.forEach(System.out::println);
复制代码
iterate 与 generate 的区别:
iterate 方法接受一个初始值,依次应用在每一个产生新值上的 Lambda
generate 不是依次对每一个新生成的值应用函数
java.util.stream.Collectors
静态导入其全部方法
counting : 统计
maxBy : 最大
minBy : 最小
summingInt : 求和为 int
summingLong : 求和为 long
summingDouble : 求和为 double
averagingInt : 平均值为 int
averagingLong : 平均值为 long
averagingDouble : 平均值为 double
joining : 聚合
toList
toSet
toCollection
toMap
toConcurrentMap
示例:
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Cat {
private String name;
private Integer age;
}
// 数据初始化
static List<Cat> cats = Arrays.asList(
new Cat("花猫", 5),
new Cat("花猫", 6),
new Cat("花猫", 10),
new Cat("花猫", 10),
new Cat("野猫", 5),
new Cat("野猫", 7),
new Cat("野猫", 7),
new Cat("野猫", 7),
new Cat("野猫", 9)
);
复制代码
将 "花猫" 和 "野猫" 进行分类
Map<String, List<Cat>> collect = cats.stream()
.collect(groupingBy(Cat::getName));
System.out.println(collect);
复制代码
统计出 "花猫" 和 "野猫" 的数量
Map<String, Long> collect = cats.stream()
.collect(groupingBy(Cat::getName, counting()));
System.out.println(collect);
复制代码
将 "花猫" 和 "野猫" 进行分类,而后每一个分类中,再按照年龄进行分类
Map<String, Map<Integer, List<Cat>>> collect = cats.stream()
.collect(groupingBy(Cat::getName, groupingBy(Cat::getAge)));
System.out.println(collect);
// 若是要多级分类,能够继续进行嵌套
复制代码
将 "花猫" 和 "野猫" 进行分类,而后每一个分类中,再按照年龄进行分类,统计出数量
Map<String, Map<Integer, Long>> collect = cats.stream()
.collect(groupingBy(Cat::getName, groupingBy(Cat::getAge, counting())));
System.out.println(collect);
复制代码
为 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
方法返回的函数是一个恒等函数,能够跳过。这种状况下,累加器对象将会直接用做归约过程的最终结果
public class MyCollector<T> implements Collector<T, List<T>, List<T>> {
@Override
public Supplier<List<T>> supplier() {
return ArrayList::new;
}
@Override
public BiConsumer<List<T>, T> accumulator() {
return List::add;
}
@Override
public BinaryOperator<List<T>> combiner() {
return (list1, list2) -> {
list1.addAll(list2);
return list1;
};
}
@Override
public Function<List<T>, List<T>> finisher() {
return Function.identity();
}
@Override
public Set<Characteristics> characteristics() {
return Collections.unmodifiableSet(EnumSet.of(
IDENTITY_FINISH,
CONCURRENT
));
}
}
复制代码
parallel()
parallelStream()
peek
建立一个空的 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);
复制代码
String str = null;
Optional<String> optionalStr = Optional.ofNullable(str);
Optional<Integer> integer = optionalStr.map(String::length);
Integer integer1 = integer.get();
System.out.println(integer1);
复制代码
使用 map 操做后,若是返回的对象自己是 Optional 包装的,那么就会组成 Option<Option<?>> ,须要使用 flatMap 打散。
方法 | 描述 |
---|---|
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 接口生成的异常 |
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<Double> futurePriceInUSD =
CompletableFuture.supplyAsync(() -> shop.getPrice(product))
.thenCombine(CompletableFuture.supplyAsync(
() -> ExchangeService.getRate(Money.EUR, Money.USD)),
(price, rate) -> price * rate
);
复制代码
使用 of
方法建立实例,静态不可变对象
合并了 LocalDate 和 LocalTime
方法名 | 是否静态方法 | 方法描述 |
---|---|---|
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 对象为模板,对某些状态进行修改建立该对象的副本 |
进行更加复杂的操做,能够使用重载版本的 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 方法中实现本身的逻辑。
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);
}
复制代码
功能:获取下一年的日期时间对象。