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);
}
複製代碼
功能:獲取下一年的日期時間對象。