最新Java8 新特性(下),Redis灵魂14问

最后

各位读者,由于本篇幅度过长,为了避免影响阅读体验,下面我就大概概括了整理了

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

| with | 否 | 以该 Temporal 对象为模板,对某些状态进行修改创建该对象的副本 |

LocalDate date = LocalDate.of(2014, 3, 18);

date = date.with(ChronoField.MONTH_OF_YEAR, 9);

date = date.plusYears(2).minusDays(10);

date.withYear(2011);

答案: 2016-09-08 。

每个动作都会创建一个新的 LocalDate 对象,后续的方法调用可以操纵前一方法创建的对象。这段代码的最后一句不会产生任何我们能看到的效果,因为它像前面的那些操作一样,会创建一个新的 LocalDate 实例,不过我们并没有将这个新创建的值赋给任何的变量。

Duration

用于比较 LocalTime 之间的时间差, Duration 类主要用于以秒和纳秒衡量时间的长短。

LocalTime time1 = LocalTime.now();

LocalTime time2 = LocalTime.of(11, 0, 0);

Duration d1 = Duration.between(time1, time2);

Period

用于比较 LocalDate 之间的时间差, Period 类主要用于以年月日衡量时间的长短。

Period tenDays = Period.between(LocalDate.of(2014, 3, 8), LocalDate.of(2014, 3, 18));

Duration 和 Period 通用方法

| 方法名 | 是否是静态方法 | 方法描述 |

| — | — | — |

| between | 是 | 创建两个时间点之间的 interval |

| from | 是 | 由一个临时时间点创建 interval |

| of | 是 | 由它的组成部分创建 interval的实例 |

| parse | 是 | 由字符串创建 interval 的实例 |

| addTo | 否 | 创建该 interval 的副本,并将其叠加到某个指定的 temporal 对象 |

| get | 否 | 读取该 interval 的状态 |

| isNegative | 否 | 检查该 interval 是否为负值,不包含零 |

| isZero | 否 | 检查该 interval 的时长是否为零 |

| minus | 否 | 通过减去一定的时间创建该 interval 的副本 |

| multipliedBy | 否 | 将 interval 的值乘以某个标量创建该 interval 的副本 |

| negated | 否 | 以忽略某个时长的方式创建该 interval 的副本 |

| plus | 否 | 以增加某个指定的时长的方式创建该 interval 的副本 |

| subtractFrom | 否 | 从指定的 temporal 对象中减去该 interval |

TemporalAdjuster

将日期调整到下个周日、下个工作日,或者是本月的最后一天。这时,你可以使用重载版本的 with 方法, 向其传递一个提供了更多定制化选择的 TemporalAdjuster 对象,更加灵活地处理日期。

LocalDate date1 = LocalDate.of(2014, 3, 18);

LocalDate date2 = date1.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));

LocalDate date3 = date2.with(TemporalAdjusters.lastDayOfMonth());

| 方法名 | 描述 |

| — | — |

| dayOfWeekInMonth | 创建一个新的日期,它的值为同一个月中每一周的第几天 |

| firstDayOfMonth | 创建一个新的日期,它的值为当月的第一天 |

| firstDayOfNextMonth | 创建一个新的日期,它的值为下月的第一天 |

| firstDayOfNextYear | 创建一个新的日期,它的值为明年的第一天 |

| firstDayOfYear | 创建一个新的日期,它的值为当年的第一天 |

| firstInMonth | 创建一个新的日期,它的值为同一个月中,第一个符合星期几要求的值 |

| lastDayOfMonth | 创建一个新的日期,它的值为当月的最后一天 |

| lastDayOfNextMonth | 创建一个新的日期,它的值为下月的最后一天 |

| lastDayOfNextYear | 创建一个新的日期,它的值为明年的最后一天 |

| lastDayOfYear | 创建一个新的日期,它的值为今年的最后一天 |

| lastInMonth | 创建一个新的日期,它的值为同一个月中,最后一个符合星期几要求的值 |

| next/previous | 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期 |

| nextOrSame/previousOrSame | 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期,如果该日期已经符合要求,直接返回该对象 |

DateTimeFormatter

处理日期和时间对象时,格式化以及解析日期时间对象是另一个非常重要的功能。新的 java.time.format 包就是特别为这个目的而设计的。这个包中,最重要的类是 DateTime-Formatter。 创建格式器最简单的方法是通过它的静态工厂方法以及常量。 像 BASIC_ISO_DATE和 ISO_LOCAL_DATE 这 样 的 常 量 是 DateTimeFormatter 类 的 预 定 义 实 例 。 所 有 的 DateTimeFormatter 实例都能用于以一定的格式创建代表特定日期或时间的字符串。

LocalDate date = LocalDate.of(2014, 3, 18);

String s1 = date.format(DateTimeFormatter.BASIC_ISO_DATE); // 20140318

String s2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE); // 2014-03-18

等同于

LocalDate date1 = LocalDate.parse(“20140318”, DateTimeFormatter.BASIC_ISO_DATE);

LocalDate date2 = LocalDate.parse(“2014-03-18”, DateTimeFormatter.ISO_LOCAL_DATE);

和老的 java.util.DateFormat 相比较,所有的 DateTimeFormatter 实例都是线程安全的。所以,你能够以单例模式创建格式器实例,就像 DateTimeFormatter 所定义的那些常量,并能在多个线程间共享这些实例。 DateTimeFormatter 类还支持一个静态工厂方法,它可以按照某个特定的模式创建格式器。

DateTimeFormatter formatter = DateTimeFormatter.ofPattern(“dd/MM/yyyy”)

LocalDate date1 = LocalDate.of(2014, 3, 18);

String formattedDate = date1.format(formatter);

LocalDate date2 = LocalDate.parse(formattedDate, formatter);

如果还需要更加细粒度的控制,DateTimeFormatterBuilder 类还提供了更复杂的格式器,你可以选择恰当的方法,一步一步地构造自己的格式器。另外,它还提供了非常强大的解析功能,比如区分大小写的解析、柔性解析(允许解析器使用启发式的机制去解析输入,不精确地匹配指定的模式) 、填充,以及在格式器中指定可选节。

DateTimeFormatter italianFormatter = new DateTimeFormatterBuilder()

.appendText(ChronoField.DAY_OF_MONTH)

.appendLiteral(". ")

.appendText(ChronoField.MONTH_OF_YEAR)

.appendLiteral(" ")

.appendText(ChronoField.YEAR)

.parseCaseInsensitive()

.toFormatter(Locale.ITALIAN);

ZoneId

之前看到的日期和时间的种类都不包含时区信息。时区的处理是新版日期和时间 API 新增加的重要功能,使用新版日期和时间 API 时区的处理被极大地简化了。新的 java.time.ZoneId 类是老版 java.util.TimeZone 的替代品。它的设计目标就是要让你无需为时区处理的复杂和繁琐而操心,比如处理日光时(Daylight Saving Time,DST)这种问题。跟其他日期和时间类一样, ZoneId 类也是无法修改的。

ZoneId romeZone = ZoneId.of(“Europe/Rome”);

地区ID都为 “{区域}/{城市}” 的格式, 这些地区集合的设定都由英特网编号分配机构 (IANA)的时区数据库提供。你可以通过 Java8 的新方法 toZoneId 将一个老的时区对象转换为 ZoneId :

ZoneId zoneId = TimeZone.getDefault().toZoneId();

一旦得到一个 ZoneId 对象,你就可以将它与 LocalDate 、 LocalDateTime 或者是 Instant 对象整合起来,构造为一个 ZonedDateTime 实例,它代表了相对于指定时区的时间点。

LocalDate date = LocalDate.of(2014, Month.MARCH, 18);

ZonedDateTime zdt1 = date.atStartOfDay(romeZone);

LocalDateTime dateTime = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45);

ZonedDateTime zdt2 = dateTime.atZone(romeZone);

Instant instant = Instant.now();

ZonedDateTime zdt3 = instant.atZone(romeZone);

ZonedDateTime

将 LocalDateTime 转换为 Instant :

LocalDateTime dateTime = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45);

Instant instantFromDateTime = dateTime.toInstant(romeZone);

将 Instant 转换为 LocalDateTime :

Instant instant = Instant.now();

LocalDateTime timeFromInstant = LocalDateTime.ofInstant(instant, romeZone);

计算时区

ZoneOffset newYorkOffset = ZoneOffset.of(“-05:00”);

日历系统

Java8 中另外还提供了4种其他的日历系统。这些日历系统中的每一个都有一个对应的日志类,分别是 ThaiBuddhistDate 、MinguoDate 、 JapaneseDate 以及 HijrahDate 。所有这些类以及 LocalDate 都实现了 ChronoLocalDate 接口,能够对公历的日期进行建模。利用 LocalDate 对象,你可以创建这些类的实例。

LocalDate date = LocalDate.of(2014, Month.MARCH, 18);

JapaneseDate japaneseDate = JapaneseDate.from(date);

等同于

Chronology japaneseChronology = Chronology.ofLocale(Locale.JAPAN);

ChronoLocalDate now = japaneseChronology.dateNow();

java8类库


@Repeatable

如果一个注解在设计之初就是可重复的,你可以直接使用它。但是,如果你提供的注解是为用户提供的,那么就需要做一些工作,说明该注解可以重复。

新增方法

| 类/接口 | 新方法 |

| — | — |

| Map | getOrDefault , forEach , compute , computeIfAbsent , computeIfPresent , merge ,putIfAbsent , remove(key,value) , replace , replaceAll |

| Iterable | forEach , spliterator |

| Iterator | forEachRemaining |

| Collection | removeIf , stream , parallelStream |

| List | replaceAll , sort |

| BitSet | stream |

Map

forEach 该方法签名为 void forEach(BiConsumer<? super K,? super V> action),作用是对 Map 中的每个映射执行 action 指定的操作,其中 BiConsumer 是一个函数接口,里面有一个待实现方法 void accept(T t, U u)。

java8之前写法:

HashMap<Integer, String> map = new HashMap<>();

map.put(1, “one”);

map.put(2, “two”);

map.put(3, “three”);

for (Map.Entry<Integer, String> entry : map.entrySet()) {

System.out.println(entry.getKey() + “=” + entry.getValue());

}

java8:

HashMap<Integer, String> map = new HashMap<>();

map.put(1, “one”);

map.put(2, “two”);

map.put(3, “three”);

map.forEach((k, v) -> System.out.println(k + “=” + v));

getOrDefault 方法就可以替换现在检测 Map 中是否包含给定键映射的惯用方法。如果 Map 中不存在这样的键映射,你可以提供一个默认值,方法会返回该默认值。

java8 之前写法:

Map<String, Integer> carInventory = new HashMap<>();

Integer count = 0;

if (map.containsKey(“Aston Martin”)) {

count = map.get(“Aston Martin”);

}

java8:

Integer count = map.getOrDefault(“Aston Martin”, 0);

putIfAbsent 方法签名为V putIfAbsent(K key, V value),作用是只有在不存在 key 值的映射或映射值为 null 时,才将 value 指定的值放入到 Map 中,否则不对 Map 做更改.该方法将条件判断和赋值合二为一,使用起来更加方便。

remove(Object key, Object value) 方法,只有在当前 Map 中 key 正好映射到 value 时才删除该映射,否则什么也不做。

replace 在 Java7 及以前,要想替换 Map 中的映射关系可通过 put(K key, V value) 方法实现,该方法总是会用新值替换原来的值.为了更精确的控制替换行为,Java8 在 Map 中加入了两个 replace() 方法,分别如下:

  • replace(K key, V value),只有在当前 Map 中 key 的映射存在时才用 value 去替换原来的值,否则什么也不做。

  • replace(K key, V oldValue, V newValue),只有在当前 Map 中 key 的映射存在且等于 oldValue 时才用 newValue 去替换原来的值,否则什么也不做。

replaceAll 该方法签名为 replaceAll(BiFunction<? super K,? super V,? extends V> function),作用是对 Map 中的每个映射执行 function 指定的操作,并用 function 的执行结果替换原来的 value,其中 BiFunction 是一个函数接口,里面有一个待实现方法 R apply(T t, U u)。

java8 之前写法:

HashMap<Integer, String> map = new HashMap<>();

map.put(1, “one”);

map.put(2, “two”);

map.put(3, “three”);

for (Map.Entry<Integer, String> entry : map.entrySet()) {

entry.setValue(entry.getValue().toUpperCase());

}

java8:

HashMap<Integer, String> map = new HashMap<>();

map.put(1, “one”);

map.put(2, “two”);

map.put(3, “three”);

map.replaceAll((k, v) -> v.toUpperCase());

merge 该方法签名为 merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction),作用是:

如果 Map 中 key 对应的映射不存在或者为 null,则将 value(不能是 null)关联到 key 上;

否则执行 remappingFunction,如果执行结果非 null 则用该结果跟 key 关联,否则在 Map 中删除 key 的映射。

Map<String, String> myMap = new HashMap<>();

myMap.put(“A”, “str01A”);

myMap.merge(“A”, “merge01”, String::concat); // str01A merge01

compute 该方法签名为 compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction) ,如果 map 里有这个 key,那么 remappingFunction 输入的 v 就是现在的值,返回的是对应 value,如果没有这个 key,那么输入的 v 是 null。

map.compute(key, (k, v) -> v == null ? newMsg : v.concat(newMsg));

computeIfAbsent 该方法签名为 V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction),作用是:只有在当前 Map 中不存在 key 值的映射或映射值为 null 时,才调用 mappingFunction,并在 mappingFunction 执行结果非 null 时,将结果跟 key 关联。

java8 之前写法:

Map<Integer, Set> map = new HashMap<>();

if (map.containsKey(1)) {

map.get(1).add(“one”);

} else {

Set valueSet = new HashSet();

valueSet.add(“one”);

map.put(1, valueSet);

}

java8:

map.computeIfAbsent(1, v -> new HashSet()).add(“yi”);

computeIfPresent 该方法签名为 V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction),作用跟 computeIfAbsent() 相反,即,只有在当前 Map 中存在 key 值的映射且非 null 时,才调用 remappingFunction,如果 remappingFunction 执行结果为 null,则删除 key 的映射,否则使用该结果替换 key 原来的映射。

Collection

removeIf 该方法签名为 boolean removeIf(Predicate<? super E> filter),作用是删除容器中所有满足 filter 指定条件的元素,其中 Predicate 是一个函数接口,里面只有一个待实现方法 boolean test(T t),同样的这个方法的名字根本不重要,因为用的时候不需要书写这个名字。

java8之前写法:

// 使用迭代器删除列表元素

ArrayList list = new ArrayList<>(Arrays.asList(“I”, “love”, “you”, “too”));

Iterator it = list.iterator();

while (it.hasNext()) {

if (it.next().length()>3) { // 删除长度大于3的元素

it.remove();

}

}

java8:

ArrayList list = new ArrayList<>(Arrays.asList(“I”, “love”, “you”, “too”));

// 删除长度大于3的元素

list.removeIf(str -> str.length() > 3);

replaceAll 该方法签名为 void replaceAll(UnaryOperator operator),作用是对每个元素执行 operator 指定的操作,并用操作结果来替换原来的元素。其中 UnaryOperator 是一个函数接口,里面只有一个待实现函数 T apply(T t)。

java8 之前写法:

// 使用下标实现元素替换

ArrayList list = new ArrayList<>(Arrays.asList(“I”, “love”, “you”, “too”));

for (int i=0; i<list.size(); i++) {

String str = list.get(i);

if (str.length()>3) {

list.set(i, str.toUpperCase());

}

}

java8:

ArrayList list = new ArrayList<>(Arrays.asList(“I”, “love”, “you”, “too”));

list.replaceAll(str -> {

if (str.length() > 3) {

return str.toUpperCase();

}

return str;

});

sort 该方法定义在List接口中,方法签名为 void sort(Comparator<? super E> c),该方法根据c指定的比较规则对容器元素进行排序。Comparator 接口我们并不陌生,其中有一个方法int compare(T o1, T o2) 需要实现,显然该接口是个函数接口。

java8 之前写法:

ArrayList list = new ArrayList<>(Arrays.asList(“I”, “love”, “you”, “too”));

Collections.sort(list, new Comparator() {

@Override public int compare(String str1, String str2) {

return str1.length() - str2.length();

}

});

java8:

ArrayList list = new ArrayList<>(Arrays.asList(“I”, “love”, “you”, “too”));

list.sort((str1, str2) -> str1.length() - str2.length());

spliterator 方法签名为 Spliterator spliterator(),该方法返回容器的可拆分迭代器。从名字来看该方法跟 iterator() 方法有点像,我们知道Iterator是用来迭代容器的, Spliterator 也有类似作用,但二者有如下不同:

  • Spliterator 既可以像 Iterator 那样逐个迭代,也可以批量迭代。批量迭代可以降低迭代的开销。

  • Spliterator 是可拆分的,一个 Spliterator 可以通过调用 Spliterator trySplit() 方法来尝试分成两个。一个是 this,另一个是新返回的那个,这两个迭代器代表的元素没有重叠。

可通过(多次)调用 Spliterator.trySplit() 方法来分解负载,以便多线程处理。

stream 和 parallelStream 分别返回该容器的 Stream 视图表示,不同之处在于parallelStream() 返回并行的 Stream。Stream 是 Java 函数式编程的核心类。

并发包


原子操作

java.util.concurrent.atomic 包提供了多个对数字类型进行操作的类,比如 AtomicInteger 和 AtomicLong ,它们支持对单一变量的原子操作。这些类在 Java8 中新增了更多的方法支持。

  • getAndUpdate —— 以原子方式用给定的方法更新当前值,并返回变更之前的值。

  • updateAndGet —— 以原子方式用给定的方法更新当前值,并返回变更之后的值。

  • getAndAccumulate —— 以原子方式用给定的方法对当前及给定的值进行更新,并返回变更之前的值。

  • accumulateAndGet —— 以原子方式用给定的方法对当前及给定的值进行更新,并返回变更之后的值。

Adder 和 Accumulator:

多线程的环境中,如果多个线程需要频繁地进行更新操作,且很少有读取的动作(比如,在统计计算的上下文中) ,Java API 文档中推荐大家使用新的类 LongAdder 、 LongAccumulator 、DoubleAdder 以及 DoubleAccumulator ,尽量避免使用它们对应的原子类型。这些新的类在设计之初就考虑了动态增长的需求,可以有效地减少线程间的竞争。

LongAddr 和 DoubleAdder 类都支持加法操作,而 LongAccumulator 和 DoubleAccumulator 可以使用给定的方法整合多个值。

LongAdder adder = new LongAdder();

adder.add(10);

long sum = adder.sum();

等同于

LongAccumulator acc = new LongAccumulator(Long::sum, 0);

acc.accumulate(10);

long result = acc.get();

ConcurrentHashMap

ConcurrentHashMap 类的引入极大地提升了 HashMap 现代化的程度,新引入的ConcurrentHashMap 对并发的支持非常友好。 ConcurrentHashMap 允许并发地进行新增和更新操作,因为它仅对内部数据结构的某些部分上锁。因此,和另一种选择,即同步式的 Hashtable 比较起来,它具有更高的读写性能。

  1. 性能

为了改善性能,要对 ConcurrentHashMap 的内部数据结构进行调整。典型情况下, map 的条目会被存储在桶中,依据键生成哈希值进行访问。但是,如果大量键返回相同的哈希值,由于桶是由 List 实现的,它的查询复杂度为O(n),这种情况下性能会恶化。在 Java8 中,当桶过于臃肿时,它们会被动态地替换为排序树(sorted tree) ,新的数据结构具有更好的查询性能(排序树的查询复杂度为O(log(n))) 。注意,这种优化只有当键是可以比较的(比如 String 或者 Number类)时才可能发生。

  1. 类流操作

ConcurrentHashMap 支持三种新的操作,这些操作和你之前在流中所见的很像:

  • forEach ——对每个键值对进行特定的操作

  • reduce ——使用给定的精简函数(reduction function) ,将所有的键值对整合出一个结果

  • search ——对每一个键值对执行一个函数,直到函数的返回值为一个非空值

以上每一种操作都支持四种形式,接受使用键、值、 Map.Entry 以及键值对的函数:

  • 使用键和值的操作( forEach 、 reduce 、 search )

  • 使用键的操作( forEachKey 、 reduceKeys 、 searchKeys )

  • 使用值的操作 ( forEachValue 、 reduceValues 、 searchValues )

  • 使用 Map.Entry 对象的操作( forEachEntry 、 reduceEntries 、 searchEntries )

注意,这些操作不会对 ConcurrentHashMap 的状态上锁。它们只会在运行过程中对元素进行操作。应用到这些操作上的函数不应该对任何的顺序,或者其他对象,抑或在计算过程发生变化的值,有依赖。

除此之外,你需要为这些操作指定一个并发阈值。如果经过预估当前 map 的大小小于设定的阈值,操作会顺序执行。使用值 1 开启基于通用线程池的最大并行。使用值 Long.MAX_VALUE 设定程序以单线程执行操作。

下面这个例子中,我们使用 reduceValues 试图找出 map 中的最大值:

ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();

Optional maxValue = Optional.of(map.reduceValues(1, Integer::max));

注意,对 int 、 long 和 double ,它们的 reduce 操作各有不同(比如 reduceValuesToInt 、reduceKeysToLong 等) 。

  1. 计数

ConcurrentHashMap 类提供了一个新的方法,名叫 mappingCount ,它以长整型 long 返回 map 中映射的数目。我们应该尽量使用这个新方法,而不是老的 size 方法, size 方法返回的类型为 int 。这是因为映射的数量可能是 int 无法表示的。

  1. 集合视图

ConcurrentHashMap 类还提供了一个名为 KeySet 的新方法,该方法以 Set 的形式返回ConcurrentHashMap 的一个视图(对 map 的修改会反映在该 Set 中,反之亦然) 。你也可以使用新的静态方法 newKeySet ,由 ConcurrentHashMap 创建一个 Set 。

Arrays

使用 parallelSort

parallelSort 方法会以并发的方式对指定的数组进行排序,你可以使用自然顺序,也可以为数组对象定义特别的 Comparator 。

使用 setAll 和 parallelSetAll

setAll 和 parallelSetAll 方法可以以顺序的方式也可以用并发的方式,使用提供的函数计算每一个元素的值,对指定数组中的所有元素进行设置。该函数接受元素的索引,返回该索引元素对应的值。由于 parallelSetAll 需要并发执行,所以提供的函数必须没有任何副作用。

int[] evenNumbers = new int[10];

Arrays.setAll(evenNumbers, i -> i * 2); // 0, 2, 4, 6…

使用 parallelPrefix

parallelPrefix 方法以并发的方式, 用用户提供的二进制操作符对给定数组中的每个元素进行累积计算。

int[] ones = new int[10];

Arrays.fill(ones, 1);

Arrays.parallelPrefix(ones, (a, b) -> a + b);

Number

Number 类中新增的方法如下。

  • Short 、 Integer 、 Long 、 Float 和 Double 类提供了静态方法 sum 、 min 和 max 。

  • Integer 和 Long 类提供了 compareUnsigned 、 divideUnsigned 、 remainderUnsigned 和 toUnsignedLong 方法来处理无符号数。

  • Integer 和 Long 类也分别提供了静态方法 parseUnsignedInt 和 parseUnsignedLong将字符解析为无符号 int 或者 long 类型。

  • Byte 和 Short 类提供了 toUnsignedInt 和 toUnsignedLong 方法通过无符号转换将参数转化为 int 或 者 long 类型 。 类似地 , Integer 类现在也提供了静态方法toUnsignedLong 。

  • Double 和 Float 类提供了静态方法 isFinite ,可以检查参数是否为有限浮点数。

  • Boolean 类现在提供了静态方法 logicalAnd 、 logicalOr 和 logicalXor ,可以在两个boolean 之间执行 and 、 or 和 xor 操作。

  • BigInteger 类提供了 byteValueExact 、 shortValueExact 、 intValueExact 和longValueExact 可以将 BigInteger 类型的值转换为对应的基础类型。不过,如果在转换过程中有信息的丢失,方法会抛出算术异常。

Math

如果 Math 中的方法在操作中出现溢出, Math 类提供了新的方法可以抛出算术异常。支持这一异常的方法包括使用 int 和 long 参数的 addExact 、 subtractExact 、 multipleExact 、incrementExact 、 decrementExact 和 negateExact 。此外, Math 类还新增了一个静态方法toIntExact , 可以将 long 值转换为 int 值。 其他的新增内容包括静态方法 floorMod 、 floorDiv和 nextDown 。

Files

Files 类最引人注目的改变是,你现在可以用文件直接产生流。通过 Files.lines 方法你可以以延迟方式读取文件的内容,并将其作为一个流。此外,还有一些非常有用的静态方法可以返回流。

  • Files.list —— 生成由指定目录中所有条目构成的 Stream 。这个列表不是递归包含的。由于流是延迟消费的,处理包含内容非常庞大的目录时,这个方法非常有用。

  • Files.walk —— 和 Files.list 有些类似,它也生成包含给定目录中所有条目的Stream 。不过这个列表是递归的,你可以设定递归的深度。注意,该遍历是依照深度优先进行的。

  • Files.find —— 通过递归地遍历一个目录找到符合条件的条目,并生成一个Stream 对象。

Reflection

Relection 接口的另一个变化是新增了可以查询方法参数信息的API,比如,你现在可以使用新增的 java.lang.reflect.Parameter 类查询方法参数的名称和修饰符,这个类被新的java.lang.reflect.Executable 类所引用, 而 java.lang.reflect.Executable 通用函数和构造函数共享的父类。

如果你想要学习Java的话,我给你分享一些Java的学习资料,你不用浪费时间到处搜了,从Java入门到精通的资料我都给你整理好了,这些资料都是我做Java这几年整理的Java最新学习路线,Java笔试题,Java面试题,Java零基础到精通视频课程,Java开发工具,Java练手项目,Java电子书,Java学习笔记,PDF文档教程,Java程序员面经,Java求职简历模板等,这些资料对你接下来学习Java一定会带来非常大的帮助,每个Java初学者都必备,请你进我的**Java技术qq交流群127522921**自行下载,所有资料都在群文件里,进去要跟大家多交流学习哦。

String

String 类也新增了一个静态方法,名叫 join 。你大概已经猜出它的功能了,它可以用一个分隔符将多个字符串连接起来。

String authors = String.join(", ", “Raoul”, “Mario”, “Alan”);

PS

泛型

Java类型要么是引用类型(比如 Byte 、 Integer 、 Object 、 List ) ,要么是原始类型(比如 int 、 double 、 byte 、 char ) 。但是泛型(比如 Consumer 中的 T )只能绑定到引用类型。这是由泛型内部的实现方式造成的。因此,在Java里有一个将原始类型转换为对应的引用类型的机制。这个机制叫作装箱(boxing)。相反的操作,也就是将引用类型转换为对应accept 方法的实现Lambda是 Function接口的 apply 方法的实现的原始类型,叫作拆箱(unboxing) 。Java还有一个自动装箱机制来帮助程序员执行这一任务:装箱和拆箱操作是自动完成的。

工具类库

Guava、Apache和lambdaj

广义归约( Collectors.reducing)

架构学习资料

准备两个月,面试五分钟,Java中高级岗面试为何越来越难?

准备两个月,面试五分钟,Java中高级岗面试为何越来越难?

准备两个月,面试五分钟,Java中高级岗面试为何越来越难?

准备两个月,面试五分钟,Java中高级岗面试为何越来越难?

准备两个月,面试五分钟,Java中高级岗面试为何越来越难?

由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

增了一个静态方法,名叫 join 。你大概已经猜出它的功能了,它可以用一个分隔符将多个字符串连接起来。

String authors = String.join(", ", “Raoul”, “Mario”, “Alan”);

PS

泛型

Java类型要么是引用类型(比如 Byte 、 Integer 、 Object 、 List ) ,要么是原始类型(比如 int 、 double 、 byte 、 char ) 。但是泛型(比如 Consumer 中的 T )只能绑定到引用类型。这是由泛型内部的实现方式造成的。因此,在Java里有一个将原始类型转换为对应的引用类型的机制。这个机制叫作装箱(boxing)。相反的操作,也就是将引用类型转换为对应accept 方法的实现Lambda是 Function接口的 apply 方法的实现的原始类型,叫作拆箱(unboxing) 。Java还有一个自动装箱机制来帮助程序员执行这一任务:装箱和拆箱操作是自动完成的。

工具类库

Guava、Apache和lambdaj

广义归约( Collectors.reducing)

架构学习资料

[外链图片转存中…(img-bdh7kxGQ-1715630705302)]

[外链图片转存中…(img-pYi4L45R-1715630705303)]

[外链图片转存中…(img-L0N9b2w4-1715630705303)]

[外链图片转存中…(img-UDq7BF9W-1715630705303)]

[外链图片转存中…(img-57z3UA1M-1715630705304)]

由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 14
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值