Java 8 的一些新特性

函数式接口

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

    composeandThen 都返回 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 指定格式
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容