Java 8 vs. Scala(二):Stream vs. Collection

来源:未知作者:编程 日期:2019/12/25 17:04 浏览:

再MFC中,定义了叁个叫做collect的类,类中有一个叫做collecttimer的函数,笔者在view类中落实对函数的调用,程序是这样写的:if(automanu卡塔尔国{if(0==m_state_collect卡塔尔(英语:State of Qatar){collect1.Collecttimer(卡塔尔;}}未来自家想每间距100ms调用叁次,求问加多机械漏刻的不二法门。

【编者按】在头里文章中,我们介绍了 Java 8和Scala的Lambda表达式相比较。在本文,将进行Hussachai Puripunpinyo Java 和 Scala 相比三部曲的第二部分,紧要关切Stream 和 Collection,本文由 OneAPM 程序猿编译整理。

在造成了plugins和extensions的加载后,进行八个甲级resource(分别是network、subnet、subnetpool和port)的map进度。map进程指的是,将次第resource的相干央求(比方创制network、删除subnet)映射到对应的管理函数的经过。APIRouter结构函数中相关代码如下:

第风姿罗曼蒂克,为大家做四个简易的牵线,collection 是有限的数据集,而 stream 是数据的体系集,能够是轻松的或极端的。

RESOURCES = {'network': 'networks',
             'subnet': 'subnets',
             'subnetpool': 'subnetpools',
             'port': 'ports'}
SUB_RESOURCES = {}
class APIRouter(base_wsgi.Router):
    ......
    def __init__(self, **local_config):
        mapper = routes_mapper.Mapper()
        ......

        mapper.connect('index', '/', controller=Index(RESOURCES))

        for resource in RESOURCES:
            _map_resource(RESOURCES[resource], resource,
                          attributes.RESOURCE_ATTRIBUTE_MAP.get(
                              RESOURCES[resource], dict()))
            resource_registry.register_resource_by_name(resource)

        for resource in SUB_RESOURCES:
            _map_resource(SUB_RESOURCES[resource]['collection_name'], resource,
                          attributes.RESOURCE_ATTRIBUTE_MAP.get(
                              SUB_RESOURCES[resource]['collection_name'],
                              dict()),
                          SUB_RESOURCES[resource]['parent'])

Streams API 是 Java 8 中新公布的 API,首要用于操作 collection 和 streaming 数据。Collections API 会改造数据集状态,而 Streams API 则不会。举例,当您调用Collections.sort(list卡塔尔(قطر‎时,该方法会对传播的参数举行排序,而调用list.stream(卡塔尔(英语:State of Qatar).sorted(卡塔尔(英语:State of Qatar)则会复制生机勃勃份数据开展操作,保持原数据不改变。您能够在那获得越来越多关于 API 数据流的新闻

map进程的主要就是调用Mapper类的函数来达成,这里首先实例化了Mapper类。

以下是小编从 Java 8 文书档案中摘出的 collections 和 streams 之间的比较。刚毅提议大家阅读 完整版。

跟着,调用其connect函数来拓宽map。那是三个最简便易行的map格局。这里特别到的url为

Streams 和 collections 有以下几点差异:

最后,依次调用_map_resource函数对RESOURCES中的各样一级resource实行map,并注册种种超级resource。向_map_resource传入的参数分别是collection(resource的聚集的称号,string)、resource(resource的称呼,string)和resource相关的品质(dict)。

  1. 无存款和储蓄。steam 不是储存数据成分的数据布局。而是经过测算操作管道从根源传输数据成分。

上边重点深入分析_map_resource函数:

2.真相是函数。对 Stream 对象操作能收获一个结实,但是不会改进原始数据。

class APIRouter(base_wsgi.Router):
    def __init__(self, **local_config):
        col_kwargs = dict(collection_actions=COLLECTION_ACTIONS,
                          member_actions=MEMBER_ACTIONS)

        def _map_resource(collection, resource, params, parent=None):
            allow_bulk = cfg.CONF.allow_bulk
            controller = base.create_resource(                                   # 1
                collection, resource, plugin, params, allow_bulk=allow_bulk,
                parent=parent, allow_pagination=True,
                allow_sorting=True)
            path_prefix = None
            if parent:
                path_prefix = "/%s/{%s_id}/%s" % (parent['collection_name'],
                                                  parent['member_name'],
                                                  collection)
            mapper_kwargs = dict(controller=controller,                          # 2
                                 requirements=REQUIREMENTS,
                                 path_prefix=path_prefix,
                                 **col_kwargs)
            return mapper.collection(collection, resource,                       # 3
                                     **mapper_kwargs)
  1. Laziness-seeking(延迟寻找):Stream 的多多操作如 filter、map、sort 和 duplicate removal(去重)能够延缓落成,意思是大家只要检查到知足供给的成分就足以回到。

  2. 或者是不受限定的:Streams 允许 Client 取丰裕多的要素直到知足有些条件停止。而 Collections 不可能如此做。

  3. 花费的。Steam 中的成分在 steam 生存期内只好被访谈一次。

_map_resource函数首要包蕴了八个步骤:

Java 和 Scala 都得以很简短地同期总括 collection 中的值。在 Java 中,你只需调用parallelStream(卡塔尔(英语:State of Qatar)* 也许stream(卡塔尔.parallel(卡塔尔(英语:State of Qatar),并非stream(卡塔尔(قطر‎。在 Scala 中,在调用别的措施从前,必得先调用 par(卡塔尔(英语:State of Qatar)函数。何况能够经过增添parallelism 来拉长程序的品质。不幸的是,大多数日子它的施行进度都卓殊慢。事实上,parallelism 是二个比较轻易被误用的意义。 点那阅读那风趣的小说

  1. 调用/neutron/api/v2/base.py中的create_resource函数来结构央浼的管理函数(即下面提到的controller);
  2. 构造传入mapper.collection函数的参数mapper_kwargs;
  3. Java 8 vs. Scala(二):Stream vs. Collection。调用mapper.collection函数来实在张开map动作。

在 JavaDoc 中, parallelStream(卡塔尔国方法的牵线是:只怕回到贰个相互的 stream(collection作为数据源),所以它也说不好回到三个串行 stream。(有人做过关于该API的商讨)

先分析create_resource函数:

图像标题

def create_resource(collection, resource, plugin, params, allow_bulk=False,
                    member_actions=None, parent=None, allow_pagination=False,
                    allow_sorting=False):
    controller = Controller(plugin, collection, resource, params, allow_bulk,
                            member_actions=member_actions, parent=parent,
                            allow_pagination=allow_pagination,
                            allow_sorting=allow_sorting)

    return wsgi_resource.Resource(controller, FAULT_MAP)

Java 的 Stream API 是延后实施的。那意味,未有一些名多少个得了操作(譬喻collect(卡塔尔(英语:State of Qatar) 方法调用),那么全部的中间调用(举例 filter 调用)是不会被推行的。延迟的流处理首即使为了优化 stream API 的施行成效。举个例子对三个数量流举行过滤、映射以至求和平运动算,通过运用延后机制,那么富有操作只要遍历叁遍,从而裁减中间调用。同一时候,延后实施允许每种操作只管理供给的多少。相反,Scala 的 collections 是即时管理的。那样是否意味,在测量试验中,Java Stream API始终优于 Scala ?要是只相比 Java 的 Stream API 和 Scala的 Collection API,那么Java Stream API 的确优于 Scala Collection API。但在 Scala 中有更加多的拈轻怕重。通过轻巧地调用toStream(卡塔尔(英语:State of Qatar),就能够将一个 Collection 转变到贰个 Stream,恐怕能够行使 view (豆蔻梢头种提供延后管理手艺的 Collection)来拍卖多少集结。

该函数首先实例化Controller类赋给controller变量,然后将controller作为参数调用/neutron/api/v2/resource.py的Resource函数。

上边粗略介绍下 Scala 的 Stream 和 View 性格

先看看Controller的布局函数:

Scala 的 Stream

class Controller(object):
    LIST = 'list'
    SHOW = 'show'
    CREATE = 'create'
    UPDATE = 'update'
    DELETE = 'delete'

    def __init__(self, plugin, collection, resource, attr_info,
                 allow_bulk=False, member_actions=None, parent=None,
                 allow_pagination=False, allow_sorting=False):
        if member_actions is None:
            member_actions = []
        self._plugin = plugin
        self._collection = collection.replace('-', '_')
        self._resource = resource.replace('-', '_')
        self._attr_info = attr_info
        self._allow_bulk = allow_bulk
        self._allow_pagination = allow_pagination
        self._allow_sorting = allow_sorting
        self._native_bulk = self._is_native_bulk_supported()
        self._native_pagination = self._is_native_pagination_supported()
        self._native_sorting = self._is_native_sorting_supported()
        self._policy_attrs = self._init_policy_attrs()
        self._notifier = n_rpc.get_notifier('network')
        self._member_actions = member_actions
        self._primary_key = self._get_primary_key()
        if self._allow_pagination and self._native_pagination:
            # Native pagination need native sorting support
            if not self._native_sorting:
                raise exceptions.Invalid(
                    _("Native pagination depend on native sorting")
                )
            if not self._allow_sorting:
                LOG.info(_LI("Allow sorting is enabled because native "
                             "pagination requires native sorting"))
                self._allow_sorting = True
        self.parent = parent
        if parent:
            self._parent_id_name = '%s_id' % parent['member_name']
            parent_part = '_%s' % parent['member_name']
        else:
            self._parent_id_name = None
            parent_part = ''
        self._plugin_handlers = {
            self.LIST: 'get%s_%s' % (parent_part, self._collection),
            self.SHOW: 'get%s_%s' % (parent_part, self._resource)
        }
        for action in [self.CREATE, self.UPDATE, self.DELETE]:
            self._plugin_handlers[action] = '%s%s_%s' % (action, parent_part,
                                                         self._resource)

Scala 的 Stream 和 Java 的迥然不一致。在 Scala Stream 中,无需调用终结操作去得到Stream 的结果。Stream 是贰个世袭 Abstractseq、 Linearseq和 GenericTraversableTemplate trait的抽象类。所以,你能够把Stream充作 SEQ。

Controller的布局函数首要开展了参数的赋值、参数的创制检查等。这里最要紧的成员变量是self._plugin_handlers,它是叁个对该resource采纳的action名称与相应管理函数名称的字典。以network那黄金时代resource为例,其_plugin_handlers如下:

倘使您不纯熟 Scala,能够将 Seq 当做 Java 里的 List。(Scala 中的 List 不是一个接口)。

{'list': 'get_networks', 'show': 'get_network', 'create': 'create_network', 'update': 'update_network', 'delete': 'delete_network'}

此处需清楚 Streams 中的成分都是延迟总结的,正因为此,Stream能够总结Infiniti数据流。就算要总计会集中的全部因素,Stream 和 List 有大器晚成致的属性。豆蔻梢头旦计算出结果,数值将被缓存。 Stream 有二个 force 函数,能够压迫评估 stream 再回到结果。注意,不要在最佳流中调用该函数,也决不强迫该 API 处理任何 stream 的操作,举例 size(卡塔尔国、tolist(卡塔尔(英语:State of Qatar)、foreach(卡塔尔国 等,那一个操作在 Scala 的 Stream 中都以隐式的。

分级表示:获取network列表,获取有个别network,创制有个别network,更新有些network和删除有些network。

在 Scala Stream 中实现 Fibonacci 数列。

持续流程会通过这么些变量来博取相应管理函数的称谓。

def fibFrom(a: Int, b: Int): Stream[Int] = a #:: fibFrom(b, a + b)
val fib1 = fibFrom(0, 1) //0 1 1 2 3 5 8 …
val fib5 = fibFrom(0, 5) //0 5 5 10 15 …
//fib1.force //Don’t do this cause it will call the function infinitely and soon you will get the OutOfMemoryError
//fib1.size //Don’t do this too with the same reason as above.
fib1.take(10) //Do this. It will take the first 10 from the inifite Stream.
fib1.take(20).foreach(println(_)) //Prints 20 first numbers

实例化后的controller变量传入/neutron/api/v2/resource.py的Resource函数:

::是 collection 中常用的连年数据的方式。而 #::意味着是接连数据只是是延迟试行的(Scala中的方法名都很自由)。

def Resource(controller, faults=None, deserializers=None, serializers=None,
             action_status=None):
    """Represents an API entity resource and the associated serialization and
    deserialization logic
    """
    default_deserializers = {'application/json': wsgi.JSONDeserializer()}
    default_serializers = {'application/json': wsgi.JSONDictSerializer()}
    format_types = {'json': 'application/json'}
    action_status = action_status or dict(create=201, delete=204)

    default_deserializers.update(deserializers or {})
    default_serializers.update(serializers or {})

    deserializers = default_deserializers
    serializers = default_serializers
    faults = faults or {}

    @webob.dec.wsgify(RequestClass=Request)
    def resource(request):
        ......
    # NOTE(blogan): this is something that is needed for the transition to
    # pecan.  This will allow the pecan code to have a handle on the controller
    # for an extension so it can reuse the code instead of forcing every
    # extension to rewrite the code for use with pecan.
    setattr(resource, 'controller', controller)
    setattr(resource, 'action_status', action_status)
    return resource

Scala 的 View

能够观望,Resource函数只是在当中的resource函数外多加了大器晚成层壳,这层壳重要是打开系列化和反种类化组件(serializers和deserializers)的配备。此中的resource函数经过webob.dec.wsgify修饰,所以种种resource的request均是提交这里的resource函数来拍卖。下边解析这么些resource函数:

再度故技重演,Scala 的 collection 是两个严俊 collection,而 view 是非严加的。View 是依照二个根底 collection 的 collection,在这之中装有的改变都会推迟奉行。通过调用 view 函数能够将从严 collection 转换来 view,也足以经过调用 force 方法调换回来。View 并不缓存结果,每回调用时才会奉行转变。宛如数据库的 View,但它是编造 collection。

    @webob.dec.wsgify(RequestClass=Request)
    def resource(request):                                          # 处理Request的函数
        route_args = request.environ.get('wsgiorg.routing_args')
        if route_args:
            args = route_args[1].copy()
        else:
            args = {}

        # NOTE(jkoelker) by now the controller is already found, remove
        #                it from the args if it is in the matchdict
        args.pop('controller', None)
        fmt = args.pop('format', None)
        action = args.pop('action', None)                                   # 获取请求中的format和action,移除controller。
        content_type = format_types.get(fmt,
                                        request.best_match_content_type())
        language = request.best_match_language()
        deserializer = deserializers.get(content_type)                      # 从deserializers中获取Content_type对应的deserializer。
        serializer = serializers.get(content_type)                          # 序列化同理。

        try:
            if request.body:
                args['body'] = deserializer.deserialize(request.body)['body']   # 将request中的body反序列化,e.g.str -> json。

            # Routes library is dumb and cuts off everything after last dot (.)
            # as format. At the same time, it doesn't enforce format suffix,
            # which combined makes it impossible to pass a 'id' with dots
            # included (the last section after the last dot is lost). This is
            # important for some API extensions like tags where the id is
            # really a tag name that can contain special characters.
            #
            # To work around the Routes behaviour, we will attach the suffix
            # back to id if it's not one of supported formats (atm json only).
            # This of course won't work for the corner case of a tag name that
            # actually ends with '.json', but there seems to be no better way
            # to tackle it without breaking API backwards compatibility.
            if fmt is not None and fmt not in format_types:
                args['id'] = '.'.join([args['id'], fmt])

            method = getattr(controller, action)                        # 从controller获取执行action的函数。
            result = method(request=request, **args)                    # 执行action,相关参数经反序列化后通过args参数传入controller。
        except Exception as e:
            mapped_exc = api_common.convert_exception_to_http_exc(e, faults,
                                                                  language)
            if hasattr(mapped_exc, 'code') and 400 <= mapped_exc.code < 500:
                LOG.info(_LI('%(action)s failed (client error): %(exc)s'),
                         {'action': action, 'exc': mapped_exc})
            else:
                LOG.exception(
                    _LE('%(action)s failed: %(details)s'),
                    {
                        'action': action,
                        'details': utils.extract_exc_details(e),
                    }
                )
            raise mapped_exc

        status = action_status.get(action, 200)
        body = serializer.serialize(result)                             # 将result序列化,e.g.json -> str。
        # NOTE(jkoelker) Comply with RFC2616 section 9.7
        if status == 204:
            content_type = ''
            body = None

        return webob.Response(request=request, status=status,           # 构造Response进行返回。
                              content_type=content_type,
                              body=body)