Java创建List和Map同时赋初值的5种⽅式
⼀、最常见的初始化⽅式
先创建,再添加元素
List
从源码可以看出:
List 的默认长度为10
递增后的长度为先前长度的 1.5 倍
最⼤长度是 Integer.MAX_VALUE,即 2,147,483,647 或 0x7f ff ff ff
List<String> list = new ArrayList<>();
list.add("str1");
list.add("str2");
list.add("str3");
当元素是静态对象时,可以使⽤静态代码块在初始化时进⾏赋值
private static List<String> static_list = new ArrayList<>();
static {
static_list.add("str1");
static_list.add("str2");
static_list.add("str3");
}
Map
从源码可以看出:
hashMap 的初始长度为 16
递增后的长度为之前的 2 倍
最⼤长度是 1<<30 - 1,即 1,073,741,824- 8 或 0x40 00 00 00 - 1
Map<String, String> map = newHashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
当元素是静态对象时,可以使⽤静态代码块在初始化时进⾏赋值
private static Map<String, String> static_map = new HashMap<>();
static {
static_map.put("key1", "value1");
static_map.put("key2", "value2");
static_map.put("key3", "value3");
}
⼆、使⽤双花括号在初始化的同时赋值
外层的 {} 定义了⼀个匿名内部类。内层的 {} 定义了⼀个实例初始化代码块。这个代码块在初始化内部类时执⾏。所以这⾥相当于定义了⼀个匿名内部类,并使⽤ add 添加元素来初始化。
但这种⽅式有⼏个缺点:
1. 使⽤匿名内部类,会有效率上的损失。当然在⼤多数情况下,这点效率都是可接受的。
2. 静态内部类持有所在外部类的引⽤。如果需要将 List 返回给到其他地⽅使⽤,可能造成内存泄漏。
List
List<String> list = new ArrayList<String>() {
{
add("str1");
add("str2");
add("str3");
}};
Map
Map<String, String> map = new HashMap<String, String>() {
{
put("key1", "value1");
put("key2", "value2");
put("key3", "value3");
}};
三、利⽤Arrays⼯具类
List
Arrays.asList使⽤了静态内部类,该类继承⾃ AbstractList,实现了 RandomAccess,内部使⽤了⼀个数组来存储元素。注意:内部定义的 ArrayList 并没有实现 List 接⼝,所以也不⽀持修改元素。
ArrayList(E[] array) {
a = quireNonNull(array);
}
public static <T> List<T> a) {
return new ArrayList<>(a);
}
查看源码可以发现,虽然 Arrays 和 ArrayList 都是在 java.utils 包下,但它们创建的 ArrayList 确是两个同名,但不同的东西。
Arrays 中声明了⼀个ArrayList 的内部类,但是该类不⽀持增删元素,如果使⽤了诸如 add ⽅法,在编
译时不会报错,但运⾏时会报UnsupportedOperationException
由于 Arrays 的 asList ⽅法使⽤了 “变长参数列表”,因此即使直接使⽤多个字符串作为参数,在编译时也会被⾃动装包成数组。
List<String> list1 = Arrays.asList(new String[] {"str1 ", "str2", "str3"});
List<String> list2 = Arrays.asList("str1 ", "str2", "str3");
四、利⽤Lists⼯具类
List
List ⼯具类提供了⼀个 newArrayList 的静态⽅法,从源码可以看出,newArrayList 实际只是对 ArrayList ⽆参初始化⽅法的封装,然后通过遍历迭代器 Iterator,将迭代器中的所有元素加⼊ List ⽽已
public static <E> ArrayList<E> newArrayList(final Iterator<? extends E> iterator) {
final ArrayList<E> list = newArrayList();
Iterators.addAll(list, iterator);
return list;
}
public static <E> ArrayList<E> newArrayList() {
return new ArrayList<>();
}
public static <T> boolean addAll(final Collection<T> collection, final Iterator<? extends T> iterator) {
boolean wasModified = false;
while (iterator.hasNext()) {
wasModified |= collection.());
}
return wasModified;
}
Lists 提供了两个⽅法:⼀个是创建⼀个空列表;⼀个是创建空列表的同时遍历迭代器,将它的值添加到列表中。
List<String> list = wArrayList();
list1.add("str1");
list1.add("str2");
java定义一维数组并赋值list1.add("str3");
注意:这⾥并不能⽤双花括号表达式直接添加元素
List<String> list = wArrayList(list.iterator());
五、利⽤Collections⼯具类
List
创建⼀个固定长度的 CopiesList,List 长度不能改变,且元素都⼀样,且也是不可改变的。Java在实现时,仅使⽤了⼀个空间,⽤来存存放元素,当N⾜够⼤时,可以节省空间和性能。
同样,和 Arrays 创建的 List ⼀样,都没有实现 List 接⼝,因此使⽤add⽅法,同样会在编译时报错
java.lang.UnsupportedOperationException
CopiesList<String> list1 = Collections.nCopies(5, "str");
此外,Collections 还提供了⼀个为 List ⼀次性添加所有元素的⽅法,弥补了原先 List 只能添加 Collections,⽽不⽀持数组的缺憾。
List<String> list2 = new ArrayList<>();
Collections.addAll(list1, new String[]{"str1", "str2", "str3"});
Collections.addAll(list1, "str4", "str5", "str6");
六、流式转化
流是 Java8 的新特性,提供了⼀种类似 SQL 语句从数据库中查询数据的⽅式,通过封装好的函数和链式调⽤,⾼阶抽象并简化操作。
它可以对传⼊流内部的元素进⾏筛选、排序、聚合等中间操作(intermediate operate),最后由最终操作(terminal operation)得到前⾯处理的结果。
通过静态的 Stream.of ⽅法接收元素,然后通过 collect ⽅法处理得到最终结果。
List
List<String> list1 = Stream.of("str1", "str2", "str3").List());
Map
Java 8 中我们可以通过 :: 关键字来访问类的构造⽅法,对象⽅法,静态⽅法。
Java8 允许在接⼝中加⼊具体⽅法,接⼝中的具体⽅法有两种,default ⽅法和 static ⽅法,identity () 就是 Function 接⼝的⼀个静态⽅法。Function.identity() 是⼀个返回⼀个跟输⼊⼀样的 Lambda 表达式对象,形式为 t -> t 。
第三个参数是合并函数,如果不指定 mergeFunction,当存在两个 key 相同的元素时,会报 java.lang.IllegalStateException: Duplicate key g1 at java.util.stream.Collectors.lambda$throwingMerger 错误。
1. key相同时当前值替换原始值
(oldVal, currVal) -> currVal
2. key相同时保留原始值
(oldVal, currVal) -> oldVal
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论