亲宝软件园·资讯

展开

Java9集合工厂方法 Java9 集合工厂方法解析

Lovnx 人气:0
想了解Java9 集合工厂方法解析的相关内容吗,Lovnx在本文为您仔细讲解Java9集合工厂方法的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:Java9集合,集合工厂方法,下面大家一起来学习吧。

使集合框架更便捷的工厂方法

JEP269中提议,为集合框架增添一些工厂方法,来使创建不可变集合类与含有少量元素的Map变得更加便捷。下文就为什么它们应运而生来展开详细的阐述。

集合框架增加工厂方法是必然的结果

Java饱受其语法臃肿的批评,比如,创建一个小而确定的集合类时(比如一个List),需要使用它的构造方法,然后将它的引用存放在局部变量中,通过引用来多次调用add()方法之后, 最后才来封装这个集合以获得不可变的视图。

早先的使用过程如下

List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list = Collections.unmodifiableList(list);

上面这个语法如此臃肿的例子在先前的版本中并不能够简化,不可变的静态集合必须在静态初始块中来填充,而不是使用更加方便的字段表达式。但是,

也不得不提一下下面这些单语句表达式

List<String> list1 = 
   Collections.unmodifiableList(new ArrayList<>(Arrays.asList("a", "b", "c")));

List<String> list2 = 
   Collections.unmodifiableList(new ArrayList<String>() {{ add("a"); add("b"); add("c"); }});

List<String> list3 = 
   Collections.unmodifiableList(Stream.of("a", "b", "c").collect(toList()));

为解决这些问题,JEP186提议了集合字面量的概念,集合字面量是一种句法表达式,采用一种类数组的方式,来创建List、Map或者其它的集合类

下面是其原始类型的简明表达方式

List<String> list = #[ "a", "b", "c" ];

没有任何新的语言特性,一切就像我们所思所想那样简明,但是这种集合字面量为什么没有被整合到Java9中去呢?取而代之的是,Java9采用了工厂方法来替代它,这其实是为了使语言改动尽量最小化,采用现有的方式,生产语法糖来达到这个目的的。

如此,集合工厂方法应运而生了。

一起来看看集合工厂方法

JEP 269的工厂方法受到类java.util.Collection和java.util.EnumSet类中的类似工厂方法的启发。 Collection提供用于创建空List,java.util.Set和Map的工厂方法,以及创建具有一个元素或键值对的单例List,Set和Map。 EnumSet提供了几个重载的of(…)工厂方法,它们采用固定或可变数量的参数,是为了更方便地创建指定元素的EnumSet。Java 9中的EnumSet模型的of()方法提供一致和通用的方式来创建包含任意类型对象的List,Set和Map。

以下工厂方法已添加到List接口中

static <E> List<E> of()
static <E> List<E> of(E e1)
static <E> List<E> of(E e1, E e2)
static <E> List<E> of(E e1, E e2, E e3)
static <E> List<E> of(E e1, E e2, E e3, E e4)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) 
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
static <E> List<E> of(E... elements)

以下工厂方法已添加到Set接口中

static <E> Set<E> of()
static <E> Set<E> of(E e1)
static <E> Set<E> of(E e1, E e2)
static <E> Set<E> of(E e1, E e2, E e3)
static <E> Set<E> of(E e1, E e2, E e3, E e4)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
static <E> Set<E> of(E... elements)

在每个方法列表中, 第一个方法创建一个空的不可修改的集合。接下来的10个方法可创建1-10个元素的不可修改集合。尽管这些方法比较混乱,但它们避免了final类型的可变参方法产生的数组分配,初始化和垃圾回收开销,这种方法还支持任意大小的集合。

以下是List和Set的示例

import java.util.List;
import java.util.Set;
public class ColDemo
{
   public static void main(String[] args)
   {
      List<String> fruits = List.of("apple", "orange", "banana");
      for (String fruit: fruits)
         System.out.println(fruit);
      try
      {
         fruits.add("pear");
      }
      catch (UnsupportedOperationException uoe)
      {
         System.err.println("unable to modify fruits list");
      }

      Set<String> marbles = Set.of("aggie", "alley", "steely");
      for (String marble: marbles)
         System.out.println(marble);
      try
      {
         marbles.add("swirly");
      }
      catch (UnsupportedOperationException uoe)
      {
         System.err.println("unable to modify marbles set");
      }
   }
}

运行后输出:

apple
orange
banana
unable to modify fruits list
steely
alley
aggie
unable to modify marbles set

以下工厂方法则添加到Map接口中

static <K,V> Map<K,V> 
   of()
static <K,V> Map<K,V> 
   of(K k1, V v1)
static <K,V> Map<K,V> 
   of(K k1, V v1, K k2, V v2)
static <K,V> Map<K,V> 
   of(K k1, V v1, K k2, V v2, K k3, V v3)
static <K,V> Map<K,V> 
   of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4)
static <K,V> Map<K,V> 
   of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5    
static <K,V> Map<K,V> 
   of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6)
static <K,V> Map<K,V> 
   of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7    
static <K,V> Map<K,V> 
   of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, 
      K k8, V v8)
static <K,V> Map<K,V> 
   of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, 
      K k8, V v8, K k9, V v9)
static <K,V> Map<K,V> 
   of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, 
      K k8, V v8, K k9, V v9, K k10, V v10)
static <K,V> Map<K,V> 
   ofEntries(Map.Entry<? extends K,? extends V>... entries)

第一个方法创建了一个空的不可变的Map,接下来10个方法创建包含1-10和键值对的Map,尽管这些方法比较混乱,但它们避免了final类型的可变参方法产生的数组分配,初始化和垃圾回收开销,且支持任意大小的Map。

虽然Map的可变参数方法近似List和Set的,但是它的每个键值对必须被包装起来,下面这个方法可以方便地将包装键值对转换为Map标准键值对:

Map.Entry<K,V> entry(K k, V v)

下面是Map的ofEntries() 和entry()方法的示例

import java.util.Map;
import static java.util.Map.entry;
public class MapDemo
{
   public static void main(String[] args)
   {
      Map<String, String> capCities = 
         Map.ofEntries(entry("Manitoba", "Winnipeg"), 
                       entry("Alberta", "Edmonton"));
      capCities.forEach((k, v) -> 
                        System.out.printf("Key = %s, Value = %s%n", k, v));
      try
      {
         capCities.put("British Columbia", "Victoria");
      }
      catch (UnsupportedOperationException uoe)
      {
         System.err.println("unable to modify capCities map");
      }
   }
}

运行后输出:

Key = Alberta, Value = Edmonton
Key = Manitoba, Value = Winnipeg
unable to modify capCities map

注意,未来的JDK版本可能会让开发者指定值类型来减少包装键值对所带来的性能开销,从entry()方法可以看出,通过它返回一个新的实现自Map.Entry的具体引用类型,我想这是为了后面把潜在特性迁移到值类型中去设下的铺垫吧。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

加载全部内容

相关教程
猜你喜欢
用户评论