• 关于

    保留字符可以做什么

    的搜索结果

问题

使用Python Flask或其他框架输出多行字符串

祖安文状元 2020-02-23 16:33:26 9 浏览量 回答数 2

问题

什么是字典树(Trie)6月5日【今日算法】

游客ih62co2qqq5ww 2020-07-13 14:47:22 53 浏览量 回答数 1

问题

时间复杂度 7月1日 【今日算法】

游客ih62co2qqq5ww 2020-07-02 23:54:51 6 浏览量 回答数 1

阿里云试用中心,为您提供0门槛上云实践机会!

0元试用32+款产品,最高免费12个月!拨打95187-1,咨询专业上云建议!

问题

应该返回false的用户输入返回true

养狐狸的猫 2019-12-01 20:00:45 8 浏览量 回答数 0

问题

什么是签名密钥?

轩墨 2019-12-01 21:06:42 1288 浏览量 回答数 0

回答

Daniel和Eldila的回答有一个问题:他们删除了整个文件中的所有引号和逗号。 当我必须要做类似的事情时,我通常要做的是首先用制表符替换所有分隔的引号和(通常)分号。 搜索: “;” 替换: \ t 由于我知道受影响的值将在哪一列中,因此我将再次搜索并替换: 搜索: ^([\ t] +)\ t([\ t] +)\ t([0-9] +),([0-9] +)\ t 替换: \ 1 \ t \ 2 \ t \ 3 \ 4 \ t ...给定带逗号的值在第三列。 您需要以“ ^”开头,以确保它从行首开始。然后,您重复([0-9] +)\ t的次数就是您想保留的原样。 ([[0-9] +),([0-9] +)在存在一个数字,一个逗号和另一个数字的位置搜索值。 在替换字符串中,我们使用\ 1和\ 2只是保留已编辑行中的值,并用\ t(制表符)将它们分开。然后,我们将\ 3 \ 4(之间没有制表符)放在数字的两个组成部分之间,并且不带逗号。之后的所有值将保留。 如果您需要文件中用分号分隔元素,则可以继续使用分号替换选项卡。但是,如果您忽略引号,则必须确保文本值本身不包含任何分号。这就是为什么我更喜欢使用TAB作为列分隔符。 我通常在支持RegExp的普通文本编辑器(EditPlus)中执行此操作,但是相同的regexp可以在任何编程语言中使用。

保持可爱mmm 2019-12-02 03:15:25 0 浏览量 回答数 0

问题

【Java学习全家桶】1460道Java热门问题,阿里百位技术专家答疑解惑

管理贝贝 2019-12-01 20:07:15 27612 浏览量 回答数 19

问题

搜索引擎背后的经典数据结构和算法 6月10日 【今日算法】

游客ih62co2qqq5ww 2020-06-15 07:32:11 0 浏览量 回答数 0

回答

在日志服务数据投递MaxCompute场景下,需要在MaxCompute表分区维度上检查数据完整性,即MaxCompute表中某个分区中数据是否已经完整。 使用保留字段__partition_time__作为表分区列,如何判断分区数据是否已完整 __partition_time__由日志的time字段计算得到,由日志真实时间按照时间格式字符串向下取整得出。其中,日志真实时间既不是投递数据的时间,也不是日志写入服务端时间。 举例:日志时间为2017-05-19 10:43:00,分区字段格式字符串配置为yyyy_MM_dd_HH_mm,每1小时投递一次。那么:无论该日志是什么时刻写入服务端,这条日志会存入MaxCompute的2017_05_19_10_00分区,计算细节参考MaxCompute投递字段说明。 如果不考虑写入了历史数据等问题,在日志实时写入的情况下,有以下两种方法判断分区数据是否已完整: 通过控制台或API/SDK判断(推荐) 使用API、SDK或者控制台获取指定Project/Logstore投递任务列表。例如API返回任务列表如下。控制台会对该返回结果进行可视化展示。 { "count" : 10, "total" : 20, "statistics" : { "running" : 0, "success" : 20, "fail" : 0 } "tasks" : [ ... { "id" : "abcdefghijk", "taskStatus" : "success", "taskMessage" : "", "taskCreateTime" : 1448925013, "taskLastDataReceiveTime" : 1448915013, "taskFinishTime" : 1448926013 }, { "id" : "xfegeagege", "taskStatus" : "success", "taskMessage" : "", "taskCreateTime" : 1448926813, "taskLastDataReceiveTime" : 1448930000, "taskFinishTime" : 1448936910 } ] } taskLastDataReceiveTime表示该批任务中最后一条日志到达服务端时的机器系统时间,对应控制台的接收日志数据时间,根据该参数判断时间为T以前的数据是否已经全部投递到MaxCompute表。 如果taskLastDataReceiveTime < T + 300s(300秒是为了容忍数据发送服务端发生错误重试)以前的每个投递任务状态都是success,说明T时刻的数据都已经入库。 如果任务列表中有ready/running状态任务,说明数据还不完整,需要等待任务执行结束。 如果任务列表中有failed状态任务,请查看原因并在解决后重试任务。您可以尝试修改投递配置,以解决投递问题。 通过MaxCompute分区粗略估计 比如在MaxCompute中以半小时做一次分区,投递任务为每30分钟一次,当表中包含以下分区: 2017_05_19_10_00 2017_05_19_10_30 当发现分区2017_05_19_11_00出现时,说明11:00之前分区数据已经完整。 该方法不依赖API,判断方式简单但结果并不精确,仅用作粗略估计。 使用自定义日志字段作为表分区列,如何判断分区数据已完整 比如日志中有一个字段date,取值:20170518,20170519,在配置投递规则时将date列映射到表分区列。 这种情况下,需要考虑date字段与写入服务端时间差,结合使用保留字段方法,根据接收日志数据时间判断。 投递成功,但MaxCompute表数据有缺失,应如何解决 MaxCompute投递任务状态成功,但表中数据缺失,一般有以下原因: 表分区列映射的日志服务字段的名称不存在。此时投递过去的列值为null,而MaxCompute表不允许分区列值为null。 表分区列映射的日志服务字段的值包含/或其他特殊符号。MaxCompute将这些字符作为保留字,不允许在分区列中出现。 遇到这些情况时,投递策略为忽略异常的日志行,并继续任务,在该次任务中其它分区正确的日志行可以成功同步。 因此,在配置字段映射不当的情况下,可能出现任务成功但是表中缺少数据的情况,请修改分区列配置。建议使用保留字段__partition_time__作为分区。 更多细节请参考MaxCompute投递相关限制说明。

保持可爱mmm 2020-03-26 23:26:49 0 浏览量 回答数 0

回答

点击后disabled掉,回调回来再重置回来######前端不限制?######我觉得这个还是前端做限制会比较合适,如果后端的 话  我暂时想到的就是ip过滤  每个IP在指定的时间内只能访问几次    不过感觉这样有点浪费资源###### 需要前后端一起限制 1.前端限制,点击后disabled掉,回调回来或者超时再重置回来 2.后端,限制用户只能在一定时间内访问该接口一次,可以借助redis的字符串的类型的SETNX 命令。 请求进入在redis中计数,后续请求直接返回,查询redis有值就返回失败,处理完毕删除redis的值 ######这个怎么限制在一定时间内哪?######你的问题有两种理解方式 第一种:用户点击N次 然后后台排队按照点击次数,一次一次的执行;第二种:用户点击n次,只执行第一次点击,其余的都不执行; 如果是第二种:你只需要在后台设置一个变量 用这个值做判断就行了  后台在执行点击指令时 把他的值修改  防止第二次点击命令进来,然后执行完成后将值恢复。至于第一种 我对java没什么了解 但是我觉得应该可以利用类似列队的方式来解决######1.后台加锁机制 2.点击之后设置为disable,等到请求结束返回信息再设置为disable, ######后端可以编码限定请求频率,例如Guava的RateLimiter。或者通过Ngnix限制###### 加一个过滤器,每次请求到的时候给 session 里面设置一个时间戳,返回的时候 removeSession 中这个值,如果第二个请求来了判断 session 里面时间戳是否满足了时间间隔,如果不满足,就直接返回一个提示,提交太频繁 ######刚看是 app,这样的话就直接记录针对设备或账号设置一个最后请求的时间戳,然后对比,一样的道理,完全可以放内存里面,每次只为一个账号保留一个时间戳就行了,也用不了多大内存######我遇到这种问题都是最简单的方法, 存session个值, 当然一个用户换个浏览器就不好用了, 或者缓存 用户名和状态, 主要还是要前台限制, 如果是定时操作, 可以用settimeout代替用户操作######突然想到  每次请求返回一个只能使用一次的随机值  处理请求前先比对该值  不知道行不行

kun坤 2020-05-30 17:26:57 0 浏览量 回答数 0

问题

配置更改(方向更改)并破坏了活动-这是它应该工作的方式吗?

LiuWH 2020-01-24 17:16:04 1 浏览量 回答数 1

问题

配置更改(方向更改)并破坏了活动-这是它应该工作的方式吗?

LiuWH 2020-01-24 17:12:41 1 浏览量 回答数 1

回答

简而言之 问题是由于您的代码正在访问iText已经清空内存到目标文件的页面。通过使用三参数Document构造函数并将immediateFlush参数设置为false,可以指示iText不要过早刷新页面。 try (Document document = new Document(pdf)) { 通过 try (Document document = new Document(pdf, pdf.getDefaultPageSize(), false)) { 一些解释 iText被设计为可以在不需要大量内存的情况下生成大量PDF(或同时存在多个PDF)的环境中使用。通过将PDF的完成部分写入其输出目标并将其从内存中删除,可以减少内存占用。特别是在创建多页文档时,通常只有当前页面和上一页保留在内存中,而之前的页面将被刷新,并将其余页面对象的内容设置为null。 因此,当您最终遍历PDF的所有页面时,除了最近的页面之外,其他所有页面的确没有它们的MediaBox条目,因此NullPointerException在尝试访问页面大小时会遇到问题。 对于像您这样的不适合使用早期刷新的用例,iText提供了上面使用的标志,以防止其早期刷新页面。 作为旁白... ...如果您想知道为什么之前没有回答您的问题:您发布了一段巨大的代码,因为您没有为data参数提供JSON字符串,甚至无法执行以重现该问题。因此,为了能够重现该问题,我不得不将您的代码缩减为重现该问题的基本核心: public void createPdf(String dest) throws IOException { PdfDocument pdf = new PdfDocument(new PdfWriter(dest)); try (Document document = new Document(pdf)) { document.setMargins(120, 36, 120, 36); document.add(new Paragraph("some content")); document.add(new AreaBreak(AreaBreakType.NEXT_PAGE)); document.add(new Paragraph("some more content")); document.add(new AreaBreak(AreaBreakType.NEXT_PAGE)); document.add(new Paragraph("still more content")); for (int i = 1; i <= document.getPdfDocument().getNumberOfPages(); i++) { System.out.println("PAGINA DEL PDF" + i); try { Rectangle pageSize = document.getPdfDocument().getPage(i).getPageSize(); // Rectangle pageSize = document.getPdfDocument().getPage(i).getMediaBox(); System.out.println("RECTANGLE....." + pageSize); } catch (Exception e) { // TODO: handle exception System.out.println("EXCEPCION RECTANGULO..." + e); } } } } 如果您自己这样做,那么您早就可以回答问题了。 回答来源:Stack Overflow

montos 2020-03-23 15:00:19 0 浏览量 回答数 0

问题

MaxCompute百问集锦(持续更新20171011)

隐林 2019-12-01 20:19:23 38430 浏览量 回答数 18

回答

Python 简史 开发 Python 3 的想法是实现一些重大的改变,如摆脱了 Python 的遗留问题:将所有字符串都呈现为 Unicode。正如 Python 的核心开发人员之一布雷特·坎农(Brett Cannon)写道: 人们有时会忘记 Python 诞生的年代。 Guido 于 1989 年 12 月开始对 Python 进行编码,并于 1991 年 2 月首次以开源形式发布。这意味着 Python 本身早于 1991 年 10 月发布的 Unicode 标准的第一版。在随后的几年中,Unicode 标准化后创建的语言选择使用基于 Unicode 编码字符串的实现。 支持任何语言的 Unicode 和文本非常重要。 Python 是一种世界语言,不仅是支持 ASCII 覆盖的罗马字母的语言,这就是 Python 3 在处理文本时将其默认设为“ Unicode”的原因。它保证了所有 Python 3 代码都将支持世界上的每个人,无论编写该代码的开发人员是否明确为其指定 Unicode 编码。 不幸的是,该团队假设每个人都将立即进行大的切换,并使 Python 3 向后不兼容,并将 Python 2 设置为维护分支。但是,许多人不想切换,因为正如改进的 PEP 所说,Python 3 是“相对于 Python 2 的温和的改进。”许多人并没有因为这些带来的不便而切换。当时,Python2、3 最大的区别是将 print 语句更改为 print() 函数语法,这破坏了很多 Python 2 代码。 结果,此后很多年 Python 2 还继续处于积极的开发中。 不过,在 2019 年,Python 3 终于成为了新 Python 软件工程师(大部分)开发的默认语言版本,现在许多公司和项目都在使用 Python 3 的主要功能:f- 字符串、Path、类型提示、异步,当然还包括 Unicode 编码。 缓慢的迭代过程 自从新的版本于 2008 年宣布以来,Python 3 市场份额增长一直很漫长: 最初,有很多理由不采用 Python 3:最重要的是,它与 Python 2 并没有向后兼容。结果导致一些 Python2 的主要库往 Python3 迁移都犹豫不决。2 向 3 转换的转折点发生在大约 2016 年左右的 Python 3.5 发行版中,该版本具有矩阵乘法、asyncio 的引入、OrderedDict 的速度改进以及类型提示的实现,这些提示为 Python3 带来了一些类似于静态语言的实用功能。 Python3 更高版本包含更多功能,例如 Pathlib 库和 f- 字符串操作。通过这些更改,人们使用了许多库(例如用于机器学习的 scikit-learn)开始了向 Python 3 的迁移。 随着越来越多的依赖关系开始升级,一些公司也开始迁移 Python3。 从互联网上的状况来看,您可能以为每个人都完成了 Python3 迁移。 在 Jetbrains 进行的一项调查中,他们制作了 IntelliJ 和 PyCharm 之类的 IDE,有 75%的个人受访者表示他们已经迁移到 Python3。一连串的博客文章都显示了相同的内容,例如,Dropbox 于 2018 年秋季详细说明了他们的迁移 Python3、Instagram 于 2017 年迁移 Python3、Facebook 于 2014 年开始迁移 Python3。在客户的敦促下,Splunk 最近也这样做了 – 往 Python3 迁移。 但是,仅仅因为 Python 2 即将到期,并不意味着公司会在一夜之间停止使用它。我们怎么知道 Python 2 仍在大量的使用?我们可以直接检查 Python 包库 PyPI 的运行情况。2016 年,PyPI 核心开发人员开始将日志发送到 Google 的 BigQuery,以便能够针对它们运行 SQL,这使得根据使用情况做出体系结构决策变得更加容易。 例如,如果要查看过去 30 天内通过 Python 版本下载了哪些库,则可以在 BigQuery 中创建一个新项目(每月查询的前 1TB 是免费的),然后运行: SELECT REGEXP_EXTRACT(details.python, r"^([^\.]+\.[^\.]+)") as python_version, COUNT(*) as download_count, FROM TABLE_DATE_RANGE( [the-psf:pypi.downloads], DATE_ADD(CURRENT_TIMESTAMP(), -31, "day"), DATE_ADD(CURRENT_TIMESTAMP(), -1, "day") ) GROUP BY python_version, ORDER BY download_count DESC LIMIT 100 尽管 Python 3 一直是社区中的主导版本至少一年,但从 PyPI 下载的单个软件包的最新数量显示,2019 年 9 月所有软件包下载中至少有 40%为 2.7 版本。诚然,这比年初的 60%有所下降,但是鉴于 EOL 距离只有数月之遥,所以这个数据仍然很重要。 在每个库的基础上,它变得有些棘手:大多数 Flask 下载都是使用 Python 3 版本完成的,但是只有 26%的 botocore 下载(适用于 Python 的 AWS 开发工具包)正在使用 Python 3。 而且,有几个库需要进行迁移:Twisted 和 PyPy(常用的 JIT 编译器)将无限期保留版本 2。 任何给定软件的寿命终止通常并不意味着该软件不再可用。这确实意味着它不再针对任何安全漏洞或添加任何其他错误修复程序进行更新。但是,不更新到 Python 3 会带来很多风险 - 最重要的是,可能会丢失安全更新,无法利用类型提示和速度提升等新功能。 为什么 Python3 迁移速度这么慢? 开个玩笑,在我写本文的时候,我的 IT 系统还在 Java 8 上运行(按今天的标准,这已经很古老了。但是根据 2018 年的 JVM 生态系统报告,Java 8 仍然是主要的开发环境。) 这就是答案:大多数大型组织,在技术新闻发布的炒作周期之外,其行动要比新闻媒体或博客想像的要慢得多。例如,大多数主要银行仍在运行 FORTRAN 和 COBOL 的编程语言系统。 因此,尽管许多公司描述了他们的迁移策略,但更多的应用软件将长期保留在 Python 2 上。 为什么会这样呢? 在所有决策中,政治发挥的作用和技术指导一样重要 例如,为了在 Facebook 上使用 Python 3,Jason Fried 从 2014 年开始重写 Python3 服务。一路走来,他犯了很多错误,更改了很多代码,并做了很多修改以使其广为人知人们正在做 Facebook 之类的事情,例如参加新的开发人员培训,从而开始使用 Python 3。然后,他与ŁukaszLanga 合作,后者将 Instagram 转换为 Python 3: 2016 年,他和 Langa 在 Facebook 上组建了一个全新的团队,以在公司内部管理 Python3。由于他们是“ Python 团队”,因此他先前提到的“公认权威”起作用。人们认为他们可以在 Facebook 上做出有关 Python 的决定。实际上,Instagram 的迁移项目本身耗时 10 个月。 Guido 和 Langa 现在工作的 Dropbox 花费了三年时间,而直到 Guido 几周前退休为止,它仍在进行中。 诚然,上面这些案例都是巨大的 Python 代码库,但您必须怀疑:如果 Python 的高层人员从事此工作需要花费这么长时间,那么对于一家公司非高层做决策来说可能要花费更多的时间。 安全问题是一个很重要的考量问题 具有讽刺意味的是,您会认为不升级将是更大的风险。但是在较大的组织中,不允许升级 Python3:管理员或安全团队向他们推送更新。在某些情况下,也不允许下载更新 PIP。如果 Python 2 是安全团队同意的默认协议,那么它可能需要做出巨大的努力才能说服人们将其切换到 3,尤其是在受到严格监管(例如医疗保健或金融)和政府的 IT 环境中。 惯性 尽管许多版本的 Linux(例如 RHEL)在 Python 2 和 Python 3 之间都包括了 Python 3,但这绝不是默认值,在 2 和 3 之间切换时,经常发现一些问题,尤其是指向系统版本的链接默认使用 Python2。Python 经历了从 2 到 3 的漫漫长路,个人和具有前瞻性的创业公司都采用了它。现在,第二大迁移将发生在大型企业从 2 开始迁移的时候。关于 Python 2,我们将看到 2020 年 40%使用率的数量进一步减少,但是变化将是递增的。 英文原文

珍宝珠 2020-01-06 10:36:04 0 浏览量 回答数 0

问题

移动推送 iOS SDK: 推送通知收不到排查步骤该做什么?

猫饭先生 2019-12-01 22:03:42 795 浏览量 回答数 0

回答

mysql的聚簇索引是指innodb引擎的特性,mysiam并没有,如果需要该索引,只要将索引指定为主键(primary key)就可以了。比如:create table blog_user( user_Name char(15) not null check(user_Name !=''), user_Password char(15) not null, user_emial varchar(20) not null unique, primary key(user_Name) )engine=innodb default charset=utf8 auto_increment=1;其中的 primary key(user_Name) 这个就是聚簇索引索引了;聚簇索引的叶节点就是数据节点,而非聚簇索引的叶节点仍然是索引节点,并保留一个链接指向对应数据块。聚簇索引主键的插入速度要比非聚簇索引主键的插入速度慢很多。相比之下,聚簇索引适合排序,非聚簇索引(也叫二级索引)不适合用在排序的场合。因为聚簇索引本身已经是按照物理顺序放置的,排序很快。非聚簇索引则没有按序存放,需要额外消耗资源来排序。当你需要取出一定范围内的数据时,用聚簇索引也比用非聚簇索引好。另外,二级索引需要两次索引查找,而不是一次才能取到数据,因为存储引擎第一次需要通过二级索引找到索引的叶子节点,从而找到数据的主键,然后在聚簇索引中用主键再次查找索引,再找到数据。innodb索引分类:聚簇索引(clustered index)    1)  有主键时,根据主键创建聚簇索引    2)  没有主键时,会用一个唯一且不为空的索引列做为主键,成为此表的聚簇索引    3) 如果以上两个都不满足那innodb自己创建一个虚拟的聚集索引辅助索引(secondary index)   非聚簇索引都是辅助索引,像复合索引、前缀索引、唯一索引 myisam索引:因为myisam的索引和数据是分开存储存储的,myisam通过key_buffer把索引先缓存到内存中,当需要访问数据时(通过索引访问数据),在内存中直接搜索                         索引,然后通过索引找到磁盘相应数据,这也就是为什么索引不在key buffer命中时,速度慢的原因     innodb索引:innodb的数据和索引放在一起,当找到索引也就找到了数据 自适应哈希索引:innodb会监控表上的索引使用情况,如果观察到建立哈希索引可以带来速度的提升,那就建立哈希索引,自 适应哈希索引通过缓冲池的B+树构造而来,                               因此建立的速度很快,不需要将整个表都建哈希索引,InnoDB 存储引擎会自动根据访问的频率和模式来为某些页建立哈希索引。自适应哈希索引不需要                               存储磁盘的,当停库内容会丢失,数据库起来会自己创建,慢慢维护索引。     聚簇索引:MySQL InnoDB一定会建立聚簇索引,把实际数据行和相关的键值保存在一块,这也决定了一个表只能有一个聚簇索引,即MySQL不会一次把数据行保存在二个地方。     1)  InnoDB通常根据主键值(primary key)进行聚簇     2) 如果没有创建主键,则会用一个唯一且不为空的索引列做为主键,成为此表的聚簇索引     3) 上面二个条件都不满足,InnoDB会自己创建一个虚拟的聚集索引 优点:聚簇索引的优点,就是提高数据访问性能。聚簇索引把索引和数据都保存到同一棵B+树数据结构中,并且同时将索引列与相关数据行保存在一起。这意味着,当你访问同一数据页不同行记录时,已经把页加载到了Buffer中,再次访问的时候,会在内存中完成访问,不必访问磁盘。不同于MyISAM引擎,它将索引和数据没有放在一块,放在不同的物理文件中,索引文件是缓存在key_buffer中,索引对应的是磁盘位置,不得不通过磁盘位置访问磁盘数据。  缺点:1) 维护索引很昂贵,特别是插入新行或者主键被更新导至要分页(page split)的时候。建议在大量插入新行后,选在负载较低的时间段,通过OPTIMIZE TABLE优化表,因为必须被移动的行数据可能造成碎片。使用独享表空间可以弱化碎片   2) 表因为使用UUId作为主键,使数据存储稀疏,这就会出现聚簇索引有可能有比全表扫面更慢,所以建议使用int的auto_increment作为主键 3) 如果主键比较大的话,那辅助索引将会变的更大,因为辅助索引的叶子存储的是主键值;过长的主键值,会导致非叶子节点占用占用更多的物理空间  辅助索引在聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找。辅助索引叶子节点存储的不再是行的物理位置,而是主键值。通过辅助索引首先找到的是主键值,再通过主键值找到数据行的数据叶,再通过数据叶中的Page Directory找到数据行。复合索引由多列创建的索引称为符合索引,在符合索引中的前导列必须出现在where条件中,索引才会被使用ALTER TABLE test.users ADD INDEX idx_users_id_name (name(10) ASC, id ASC) ; 前缀索引当索引的字符串列很大时,创建的索引也就变得很大,为了减小索引体积,提高索引的扫描速度,就用索引的前部分字串索引,这样索引占用的空间就会大大减少,并且索引的选择性也不会降低很多。而且是对BLOB和TEXT列进行索引,或者非常长的VARCHAR列,就必须使用前缀索引,因为MySQL不允许索引它们的全部长度。使用:列的前缀的长度选择很重要,又要节约索引空间,又要保证前缀索引的选择性要和索引全长度选择性接近。 唯一索引唯一索引比较好理解,就是索引值必须唯一,这样的索引选择性是最好的 主键索引主键索引就是唯一索引,不过主键索引是在创建表时就创建了,唯一索引可以随时创建。说明主键和唯一索引区别     1) 主键是主键约束+唯一索引     2) 主键一定包含一个唯一索引,但唯一索引不是主键     3) 唯一索引列允许空值,但主键列不允许空值     4) 一个表只能有一个主键,但可以有多个唯一索引 索引扫描方式:紧凑索引扫描(dense index):在最初,为了定位数据需要做权表扫描,为了提高扫描速度,把索引键值单独放在独立的数据的数据块里,并且每个键值都有个指向原数据块的指针,因为索引比较小,扫描索引的速度就比扫描全表快,这种需要扫描所有键值的方式就称为紧凑索引扫描 松散索引扫描(sparse index):为了提高紧凑索引扫描效率,通过把索引排序和查找算法(B+trre),发现只需要和每个数据块的第一行键值匹配,就可以判断下一个数据块的位置或方向,因此有效数据就是每个数据块的第一行数据,如果把每个数据块的第一行数据创建索引,这样在这个新创建的索引上折半查找,数据定位速度将更快。这种索引扫描方式就称为松散索引扫描。 覆盖索引扫描(covering index):包含所有满足查询需要的数据的索引称为覆盖索引,即利用索引返回select列表中的字段,而不必根据索引再次读取数据文件索引相关常用命令:1) 创建主键 CREATE TABLE pk_tab2 (  id int(11) NOT NULL AUTO_INCREMENT,  a1 varchar(45) DEFAULT NULL,  PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8; 2) 创建唯一索引create unique index indexname on tablename(columnname); alter table tablename add unique index indexname(columnname); 3) 创建单列一般索引create index indexname on tablename(columnname);alter table tablename add index indexname(columnname); 4) 创建单列前缀索引create index indexname on tablename(columnname(10));    //单列的前10个字符创建前缀索引alter table tablename add index indexname(columnname(10)); //单列的前10个字符创建前缀索引 5) 创建复合索引create index indexname on tablename(columnname1,columnname2);    //多列的复合索引create index indexname on tablename(columnname1,columnname2(10));    //多列的包含前缀的复合索引alter table tablename add index indexname(columnname1,columnname2); //多列的复合索引alter table tablename add index indexname(columnname1,columnname(10)); //多列的包含前缀的复合索引 6) 删除索引drop index indexname on tablename;;alter table tablename drop  index indexname; 7) 查看索引show index from tablename;show create table pk_tab2;作者:大树叶 来源:CSDN 原文:https://blog.csdn.net/bigtree_3721/article/details/51335479 版权声明:本文为博主原创文章,转载请附上博文链接!

孟志昂 2019-12-02 01:45:11 0 浏览量 回答数 0

回答

Re我和iDBCloud登录数据库的故事 11到13年做DBA的时候,最早接触的是iDB,我的理解之所以叫iDB应该是表达我的数据库的含义吧,估计我还是上学的时候就已经有了,目前iDB已经迭代到3.0,明年初会发布4.0,从DBA视角上看iDB就是可以review业务SQL,自动执行线上DDL,业务数据提取的申请和审批,WEB上的数据查询,最近做产品经理后才有机会系统的审视iDB(一个包含研发支撑、安全管控的企业级数据库管理产品),支撑了淘宝、天猫、支付宝(现在叫蚂蚁金服)的研发流程,保障了每年的双十一,但iDB Cloud与iDB不是一个产品,iDB是企业版的数据库管理产品,iDB Cloud则定位于个人版数据管理,相比企业中的流程约束,iDB Cloud更期望给大家提供在约束下的易用性最大化的灵活数据管理服务! ------------------------- Re我和iDBCloud登录数据库的故事 这个月实例信息-实时性能UI改版发布,新版看起来还是比较舒服的!这个我在5元RDS大促时买的,没有跑业务,所以指标都是0,哈哈 实时性能的原型取自阿里DBA团队的传奇(朱旭)之手:orzdba,貌似很久之前已经开源,谷歌下便知! 翻出之前做DBA使用orzdba观察测试机器压测的截图,orzdba是用perl写的,检查项还是蛮多的,比如io吞吐量、rt、主机的load、swap、innodb row、innodb状态,这些是iDB Cloud没有的功能,iDB Cloud通过用户登录账号访问数据库,只能拿到MySQL进程内存中的状态信息,没有权限拿到主机指标,不过innodb相关信息是可以拿到的,但是考虑一般只有DBA才会关注这些细节,所以没开放,不知道大家还会关注什么指标?有没有办法拿到主机的指标? ------------------------- 回5楼ringtail的帖子 刷新页面,类似关闭并重新打开,啥都没了,这个应该是正常的行为,话说为什么要刷新呢,我记得首页性能指标每5分钟自动刷新,即使点击页面上提供的刷新是没啥事的,而实时性能是每4秒更新一行的,还有什么场景要刷洗整个页面是我没想到的吗? ------------------------- 回7楼ringtail的帖子 目前据我所知,真心还做不到刷新不丢iDB Cloud已经打开的选项卡、sql语句和执行结果什么的,现在只能在刷新时加一个“导航确认”,减少手痒式误刷新,哈哈 ------------------------- Re我和iDBCloud登录数据库的故事 翻工单时,发现有人关心使用iDB Cloud是否会收取流量费,我也没搞清楚,于是问了几个同事,终于把场景基本覆盖了,最终结论: 只要你不把你的RDS实例切换成外网(公网)模式的同时再导出或查询数据就不会收取流量费! 由于那几个工单已经关闭,我就在这里回复下大家,希望那几个朋友能看到 ------------------------- 回9楼yzsind的帖子 一定不会辜负领导的期望,努力工作,争取升职加薪,当上总经理,出任ceo,迎娶白富美,想想还有点小激动 ------------------------- 回10楼佩恩六道的帖子 可能文字不好理解整体的流量计费情况,中午用我那小学的美术细胞,完成了一副“巨作”! ------------------------- Re我和iDBCloud登录数据库的故事 刚才看到一个工单(iDB Cloud点击登录无效),这个工单已经处理完毕,但我觉得可以把售后同学的方法和大家分享下! 以后遇到点击登录无效、登录后菜单栏点击无效、页面展示不全,很可能是浏览器兼容设置的问题! 浏览器兼容设置的问题: 1.检查浏览器是否安装了AdBlockPlus(火狐浏览器的一个扩展),用火狐浏览器的用户遇到类似问题要注意这一点 2.IE浏览器的话就调整下兼容性模式(http://jingyan.baidu.com/article/fcb5aff791bb47edaa4a7115.html ),并进入开发者模式再测试下IDB Cloud 如果上述2招还是解决不了,记得留言给我! ------------------------- Re我和iDBCloud登录数据库的故事 今天看工单时发现有个朋友反馈,包含mediumblob类型字段的表在做导出后,导出文件中没有mediumblob类型字段! 其实导出时默认是不会导出BLOB类型字段,但是在导出-高级选项中是可以选择导出BLOB,但是BLOB字段只能以16进制格式导出,试想一个WORD文档或者一首歌曲,16进制导出后,没啥意义! BOLB字段支持WEB界面上传和下载,是原文件呀,哈哈! ------------------------- Re我和iDBCloud登录数据库的故事 未来几天休假,去考驾照 ------------------------- Re我和iDBCloud登录数据库的故事 看工单和论坛中,有用户会抱怨产品不好用,然后就消失了,真的好可惜! 作为产品经理是很想倾听这些抱怨背后的真实想法,期待可以直接对话,无论是功能缺失,还是操作不便,哪怕是使用上的一种感觉或产品散发的味道不对都可以,不求需求,只求对话! ------------------------- Re我和iDBCloud登录数据库的故事 感谢你的关注和支持! 产品说到底不是产品经理个人的,也不是哪个企业的,而是用户的产品,水能载舟亦能覆舟,产品经理和企业只不过在帮用户把需求实现而已,所以我们会一直坚持下去,坚持和用户一起把iDB Cloud做得更好 ------------------------- Re我和iDBCloud登录数据库的故事 最近几天公司感冒发烧的同学很多,我也是坚持了好几天才沦陷的,这是在我记忆中来杭州4年第一次发烧,看来20多年在东北积累的体质终于被消耗殆尽,不过意外收获是在高烧间隔清醒之际对最近自己的所作所为反倒有了一些悔悟,有些是工作上,有些是做人上 ------------------------- 回24楼zhouzhenxing的帖子 可以的,iDB Cloud对RDS公网和私网模式都是支持的! 你可以在RDS控制台-账号管理中 新建你的数据库账号,然后还是在RDS控制台的右上角,点击“登录数据库”就可以进入iDB Cloud了,建议你先自己试着玩玩,有困惑的话我们一同讨论 ------------------------- 回24楼zhouzhenxing的帖子 iDB Cloud在官网上有2个手册,写的比较官方,可能对你用处不大,我其实不太喜欢写什么手册,如果一个产品做的体验不好,只能靠手册来弥补还是有点low,不过我已经在想如何不low了,还是那句话 有困惑的话我们一同讨论 http://help.aliyun.com/doc/view/13526530.html?spm=0.0.0.0.6W7Qx1 http://help.aliyun.com/view/11108238_13861850.html?spm=5176.7224961.1997285473.4.Irtizv ------------------------- Re我和iDBCloud登录数据库的故事 都说在产品上做加法容易,做减法难,我理解无论产品功能还是工作上,给予总会得到别人的喜欢,而要求或收回时会得到对方的负面情绪,因此趋利避害,尽量不做减法,但有时候很难避免,这就要想想为什么要做减法? 多数都是之前错误选择,做了过多的加法,因为普通的加法很好做,人们往往会趋之如骛,但是真正、正确的加法是要在拒绝几十到上百种选择基础上的最终选择,将复杂解决方案以极简形式展现出来,而不是解决方案和功能的堆积,所以未经严格挑选的加法对产品是有害的,工作也一样,不要贸然接受新工作,保证核心精力投入到核心工作上,摊子铺得太大,一定会遇到心力瓶颈,而心力一旦枯竭,再强的脑力也无法施展,任何一项工作都是以大量心力付出为前提,脑力提升我找到了一些办法,心力提升却一筹莫展,所以只好专注,要不全心投入,要不置身事外,今后功能和工作都要适时做做减法了! ------------------------- Re我和iDBCloud登录数据库的故事 今天有个同事转给我一个工单,说从深圳云管理系统界面的iDB Cloud上看到库是utf8,而后端开发人员说库是gbk的,我查看了工单中截图附件(RDS控制台-参数设置),虽然从工单中无法完全断定用户遇到的问题,我还是大胆猜测下: 我看到截图上的character_set_server参数,首先character_set_server是RDS唯一开放的关于字符集的参数,但其实这个参数与用户在iDB Cloud上看到数据是否乱码没有关系,character_set_server其实就是默认的内部操作字符集,只有当字段->表->库都没有设置CHARACTER SET,才会使用character_set_server作为对应字段-表-库的默认字符集! 透露一个秘诀(传男也传女): (1)让你的字段-表-库的字符集都是utf8; (2)在iDB Cloud-命令窗口执行set names utf8;#会将character_set_client、character_set_connection和character_set_results都设置成utf8 只要让(1)和(2)字符集保持一致(utf8、gbk、latin1等),乱码就搞定了! 不清楚为什么截图会变成上面这样!把在iDB Cloud-命令窗口上执行的命令和结果也粘下 mysql>set names gbk; 执行成功,花费 7.59 ms. mysql>show  variables like '%char%'; +--------------------------+----------------------------------+ | Variable_name            | Value                            | +--------------------------+----------------------------------+ | character_set_client     | gbk                              | | character_set_connection | gbk                              | | character_set_database   | gbk                              | | character_set_filesystem | binary                           | | character_set_results    | gbk                              | | character_set_server     | gbk                              | | character_set_system     | utf8                             | | character_sets_dir       | /u01/mysql/share/mysql/charsets/ | +--------------------------+----------------------------------+ 共返回 8 行记录,花费 10.51 ms. mysql>set names utf8; 执行成功,花费 7.32 ms. mysql>show  variables like '%char%'; +--------------------------+----------------------------------+ | Variable_name            | Value                            | +--------------------------+----------------------------------+ | character_set_client     | utf8                             | | character_set_connection | utf8                             | | character_set_database   | gbk                              | | character_set_filesystem | binary                           | | character_set_results    | utf8                             | | character_set_server     | gbk                              | | character_set_system     | utf8                             | | character_sets_dir       | /u01/mysql/share/mysql/charsets/ | +--------------------------+----------------------------------+ 共返回 8 行记录,花费 10.32 ms. ------------------------- Re我和iDBCloud登录数据库的故事 你的专属BUG: 发现时间 资深用户 专属BUG 2015-02-03 23:06 啊啊啊啊8  实例信息-实时性能-参数说明-【delete】 表示InnoDB存储引擎表的写入(删除)记录行数 ------------------------- Re我和iDBCloud登录数据库的故事 用户“夫子然”反馈说iDB Cloud感觉没phpMyAdmin方便! 非常感谢这个用户的反馈,我先谈下我的理解,每个人使用产品都有一些固定的用例(use case),我无法承诺针对任何人的任何用例,都做到最短操作路径(方便),这个用户抛出的问题也是我一直在思考的,虽然无法100%,但是我们可以覆盖主流用例,只要绝大多数的常规操作室是方便的,少数非经常用的操作路径长点,应该能接受吧,我们已经在行动! 今天iDB Cloud发布了2.0.2,一个主要变化就是在左侧对象列表上增加了“列”和“索引”,正是我们分析数据看到在众多数据库对象中表的操作是最频繁的,而在表的操作中“列“和”索引“是最频繁的,这个版本将对“列”和“索引”的操作前置,缩短了主流用例路径,与用户“夫子然”的建议不谋而合,这只是开始,只要我们深挖,与功能和体验死磕,终有一天会让大家说iDB Cloud比phpMyAdmin方便! ------------------------- 回31楼sqlserverdba的帖子 非常感谢! 有你们作为后盾,有用户支持,才有iDB Cloud的现在和未来! ------------------------- 消失了几天,终于把科目三和科目四搞定了,昨天终于拿到驾照了之前在【17楼】总结了科目二的一些体会,今天也分享下科目三的一点点感受! 考试前几天,教练说是智能考(据说智能考比较简单,通过率很高),结果就留出考前2天练车时间,结果阴差阳错的换成了人工考(貌似是我们车是4个大老爷们,听教练说他一年最多抽到2次人工考就算多的啦,对此我只能呵呵),现在的问题就来了,4个人2天练车时间,一个人半天,那就从早到晚的练呗,我先简单描述下整个过程! 1.心态(1)从开始练车到考试通过,心情没有特别大的起伏,不过考前失眠还是有的,哈哈(2)另外三个人,有的信心满满,有的吊儿郎当,有的不言不语,我应该也属于不言不语那种 2.练习(1)4个人轮流练,虽然一天下来很累,但还能挺住,开的时好时坏,不过总体上在变好(2)开车的时候几乎意识不到什么的,关键是在后座自己去琢磨,回忆自己错在哪里,为什么会错 3.考试(1)考试单上说7:00考试,结果在寒风中等了1个小时,终于盼来了考官,一共5辆车考试,我们是第二辆车(2)第一辆车是2男2女,2女都挂,当时我们第二辆车是被要求跟在第一辆车后面的,所以看的一清二楚,比如连续3次手刹未放下导致起步失败、4档走转弯到对向车道等(3)接下来到我们了,4男0女,结果挂了2男(信心满满和吊儿郎当) 上面只是简单介绍了科目三过程,下面才是干货! 每年都有成千上万的人拿到驾照,我不认为自己牛,只是把我个人的应对方法和背后的原因拿出来分享下!练车其实就是教练的心智模型-翻译-语言-反译-我们的心智模型,让我们知道在什么情况做什么动作,预测路况,只要我们关于开车拥有了自己的心智模,开车就变成了一种本能,就像一旦学会了骑自行车,很难失去这种技能,在练车之前,我们是有自己关于开车的心智模型的,正所谓没吃过猪肉也见过猪跑,但是我们想想自己关于开车的心智模型是正确的吗?显然不是,不信你就试试去开车吧,抛开被交警抓之外,我想应该也能开起来,至于开的好不好,会不会一直开得好,我说不准,但是绝大多数人一定是开不好的,所以我们报驾校,除了硬性法律规定,驾校教练的确交会了很多东西,虽然很多是应试的技巧,这里就顺便说下这些技巧,技巧具体内容每家教练都会教的,而我想说的技巧其实就是“语言”,通过教练的“心智模型”-翻译出来的“语言”,接下来我们要做什么,“反译”将教练开车技巧的“语言”理解,首先你要虚心去接受,然后再去观察或运用,根据反馈把坏的放弃,把好的保留以便修正自己关于开车的“心智模型”,而“心智模型”最快速的形成方式就是亲身体验,所以一定要实战、要开车,还要经常开车,不断改进关于开车的“心智模型”,拿3个案例具体说下吧!【吊儿郎当】这两天都是下午才过来练车,开车时教练说一句话,他有十句等着,其中五句是解释自己为什么要这么做,另外五句是在问如果这种情况应该怎么做,如果那种情况怎么做,总是在关注自己想象中的场景,而不关注自己正在体验的场景,所以学来学去还是最初始的关于开车的“心智模型”,失败在“反译”这一步,认为只要听过就会了,结果被考官判直接挂掉并不予补考机会 【信心满满】与我们一直练车,对教练的话言听计从,而且也理解了,如果是上学时的考试或科目三智能考试一定没问题,但是面对人工考,评判是由交警而不是电脑,结果转向时没有观察后视镜,被考官迫停在路中间后开始补考,然后还是转向时没有观察后视镜,在路中间起步,之前学的技巧中没有应对的方法,结果还是挂了,教练也很惋惜,如果说他的失败,败于没有改进自己关于开车的“心智模型”,其实“反译”他做的很好,但是在运用、观察和反馈分析上做的不好,“心智模型”不是统一的标准,一定是个性化的,一定是自己认为是好的反馈、行为积累起来的,也只有“心智模型”才能在任何情况下帮助你做出判断,判断效果就取决于“心智模型”是否成熟,成熟的“心智模型”可以让在紧张、突发等情况下依然做出正确的判断,因为那是一种本能 【我】总说别人不好之处,也谈谈我自己,自然这些都是我事后分析总结的,练车过程中可没有感受到,我做的事情也很简单,就是“反译”和改进我的“心智模型”,“反译”,教练说什么,我就听什么,开车时来不及想,就在后座时在脑中模拟上演之前的场景并不断上演我不断修正的剧本,比如我的离合器总是抬的很快,经常熄火,特别是在路况复杂、指令突然时根本来不及思考如何应对,只能靠本能的时候,往往还是会快速抬离合器,因为我的“心智模型”中就是这么认为的,你可以说是离合器太低、座位太靠后,这些都是理由,如果是理由,那就去解决吧!我是这样做的,强制自己将抬离合器的动作拆成3步,即使不开车时也经常练习,慢慢的就变成了“心智模型”的一部分,自然在任何场景下都不会再出现离合器抬快熄火的情况了,这只是一个细节,其他细节也是类似,慢慢我的“心智模型”就建立起来了,开车技巧是很有用的,关键是你要理解这些技巧是要解决什么问题,你要解决相同问题时的做法是否相同,如果有不同之处是否正确,要去不断验证,如果是正确的,就改进到你的“心智模型”吧! PD不光光是要把产品做好,我认为一个好PD应该能让整个世界变得更好! ------------------------- Re我和iDBCloud登录数据库的故事 近期iDB Cloud将更名:DMS DMS (data management service) 数据管理服务 iDB Cloud从RDS起步,目前已经覆盖包括RDS、ADS、TAE,未来2个月还会覆盖万网和DRDS,同时ECS也开始兼容,“DMS”请各位新老用户,继续支持! ------------------------- Re我和iDBCloud登录数据库的故事 1.使用HTTPS iDB Cloud这个4月份中旬版本就会支持HTTPS,敬请期待! 2.设置账号是否允许登录iDB 3.31 会发布一个版本,这版本其中一个功能就是授权登录,允许实例owner设置该实例是否允许别人访问,允许谁可以访问 有如此心犀相通的用户,夫复何求!!! 还有什么建议? ------------------------- 回38楼pillowsky的帖子 好的,我先逐条对照分析下 ------------------------- Re我和iDBCloud登录数据库的故事 RDS数据库?RDS控制台-账号管理,检查下账号对不对,不行就重置密码 ------------------------- Re我和iDBCloud登录数据库的故事 3.31 DMS(原iDB Cloud) 在RDS上新版本发布! 【实例授权】 DMS for MySQL 2.1发布! 【会话统计】 DMS for SQL Server 2.0发布! 【E-R图】 【对象列表】 ------------------------- Re我和iDBCloud登录数据库的故事 你是想听客服回复?算了,我还是从DMS PD 看RDS的视角来分享下吧! RDS是一个数据库,在数据库之外包装了一些东西,帮用户做了备份恢复、HA、监控等,回到你提到的账号,root账号在MySQL里是权限最大的,也是风险最大的,为了保证RDS这些备份恢复、HA能7*24小时为你服务,所以就不能让你的账号去影响到这些组件,不然你一个误操作把实例关闭了怎么办,但是我承认目前RDS在控制台上提供的账号的确限制比较死,所以在RDS上你是无法获取root账号的,话说你要root权限做什么,你说的数据库创建在RDS控制台上提供功能了 ------------------------- 回46楼苗教授的帖子 客气了,也不知道能不能帮上你! 如果从外看RDS的使用的话,可以在RDS控制台上去管理RDS实例(用用就熟悉了),或者直接调用OPEN API来完成实例管理操作,然后针对RDS实例中数据管理,就可以登录DMS,有几个常用链接发你看看,有问题可以在这里继续探讨! DMS: http://idb.rds.aliyun.com/ DMS 功能介绍: http://docs.aliyun.com/#/rds/getting-started/database-manage&login-database OPEN API: http://docs.aliyun.com/?spm=5176.383715.9.5.1LioEO#/rds/open-api/abstract RDS控制台: https://rds.console.aliyun.com/console/index#/

佩恩六道 2019-12-02 01:21:37 0 浏览量 回答数 0

回答

1. 原生 DOM 操作 VS 通过框架封装操作。 这是一个性能 vs. 可维护性的取舍。框架的意义在于为你掩盖底层的 DOM 操作,让你用更声明式的方式来描述你的目的,从而让你的代码更容易维护。没有任何框架可以比纯手动的优化 DOM 操作更快,因为框架的 DOM 操作层需要应对任何上层 API 可能产生的操作,它的实现必须是普适的。针对任何一个 benchmark,我都可以写出比任何框架更快的手动优化,但是那有什么意义呢?在构建一个实际应用的时候,你难道为每一个地方都去做手动优化吗?出于可维护性的考虑,这显然不可能。框架给你的保证是,你在不需要手动优化的情况下,我依然可以给你提供过得去的性能。 2. 对 React 的 Virtual DOM 的误解。 React 从来没有说过 “React 比原生操作 DOM 快”。React 的基本思维模式是每次有变动就整个重新渲染整个应用。如果没有 Virtual DOM,简单来想就是直接重置 innerHTML。很多人都没有意识到,在一个大型列表所有数据都变了的情况下,重置 innerHTML 其实是一个还算合理的操作... 真正的问题是在 “全部重新渲染” 的思维模式下,即使只有一行数据变了,它也需要重置整个 innerHTML,这时候显然就有大量的浪费。 我们可以比较一下 innerHTML vs. Virtual DOM 的重绘性能消耗: innerHTML: render html string O(template size) + 重新创建所有 DOM 元素 O(DOM size)Virtual DOM: render Virtual DOM + diff O(template size) + 必要的 DOM 更新 O(DOM change) Virtual DOM render + diff 显然比渲染 html 字符串要慢,但是!它依然是纯 js 层面的计算,比起后面的 DOM 操作来说,依然便宜了太多。可以看到,innerHTML 的总计算量不管是 js 计算还是 DOM 操作都是和整个界面的大小相关,但 Virtual DOM 的计算量里面,只有 js 计算和界面大小相关,DOM 操作是和数据的变动量相关的。前面说了,和 DOM 操作比起来,js 计算是极其便宜的。这才是为什么要有 Virtual DOM:它保证了 1)不管你的数据变化多少,每次重绘的性能都可以接受;2) 你依然可以用类似 innerHTML 的思路去写你的应用。 3. MVVM vs. Virtual DOM 相比起 React,其他 MVVM 系框架比如 Angular, Knockout 以及 Vue、Avalon 采用的都是数据绑定:通过 Directive/Binding 对象,观察数据变化并保留对实际 DOM 元素的引用,当有数据变化时进行对应的操作。MVVM 的变化检查是数据层面的,而 React 的检查是 DOM 结构层面的。MVVM 的性能也根据变动检测的实现原理有所不同:Angular 的脏检查使得任何变动都有固定的 O(watcher count) 的代价;Knockout/Vue/Avalon 都采用了依赖收集,在 js 和 DOM 层面都是 O(change): - 脏检查:scope digest O(watcher count) + 必要 DOM 更新 O(DOM change) - 依赖收集:重新收集依赖 O(data change) + 必要 DOM 更新 O(DOM change)可以看到,Angular 最不效率的地方在于任何小变动都有的和 watcher 数量相关的性能代价。但是!当所有数据都变了的时候,Angular 其实并不吃亏。依赖收集在初始化和数据变化的时候都需要重新收集依赖,这个代价在小量更新的时候几乎可以忽略,但在数据量庞大的时候也会产生一定的消耗。 MVVM 渲染列表的时候,由于每一行都有自己的数据作用域,所以通常都是每一行有一个对应的 ViewModel 实例,或者是一个稍微轻量一些的利用原型继承的 "scope" 对象,但也有一定的代价。所以,MVVM 列表渲染的初始化几乎一定比 React 慢,因为创建 ViewModel / scope 实例比起 Virtual DOM 来说要昂贵很多。这里所有 MVVM 实现的一个共同问题就是在列表渲染的数据源变动时,尤其是当数据是全新的对象时,如何有效地复用已经创建的 ViewModel 实例和 DOM 元素。假如没有任何复用方面的优化,由于数据是 “全新” 的,MVVM 实际上需要销毁之前的所有实例,重新创建所有实例,最后再进行一次渲染!这就是为什么题目里链接的 angular/knockout 实现都相对比较慢。相比之下,React 的变动检查由于是 DOM 结构层面的,即使是全新的数据,只要最后渲染结果没变,那么就不需要做无用功。 Angular 和 Vue 都提供了列表重绘的优化机制,也就是 “提示” 框架如何有效地复用实例和 DOM 元素。比如数据库里的同一个对象,在两次前端 API 调用里面会成为不同的对象,但是它们依然有一样的 uid。这时候你就可以提示 track by uid 来让 Angular 知道,这两个对象其实是同一份数据。那么原来这份数据对应的实例和 DOM 元素都可以复用,只需要更新变动了的部分。或者,你也可以直接 track by $index 来进行 “原地复用”:直接根据在数组里的位置进行复用。在题目给出的例子里,如果 angular 实现加上 track by $index 的话,后续重绘是不会比 React 慢多少的。甚至在 dbmonster 测试中,Angular 和 Vue 用了 track by $index 以后都比 React 快: dbmon (注意 Angular 默认版本无优化,优化过的在下面) 顺道说一句,React 渲染列表的时候也需要提供 key 这个特殊 prop,本质上和 track-by 是一回事。 4. 性能比较也要看场合 在比较性能的时候,要分清楚初始渲染、小量数据更新、大量数据更新这些不同的场合。Virtual DOM、脏检查 MVVM、数据收集 MVVM 在不同场合各有不同的表现和不同的优化需求。Virtual DOM 为了提升小量数据更新时的性能,也需要针对性的优化,比如 shouldComponentUpdate 或是 immutable data。 初始渲染:Virtual DOM > 脏检查 >= 依赖收集小量数据更新:依赖收集 >> Virtual DOM + 优化 > 脏检查(无法优化) > Virtual DOM 无优化大量数据更新:脏检查 + 优化 >= 依赖收集 + 优化 > Virtual DOM(无法/无需优化)>> MVVM 无优化 不要天真地以为 Virtual DOM 就是快,diff 不是免费的,batching 么 MVVM 也能做,而且最终 patch 的时候还不是要用原生 API。在我看来 Virtual DOM 真正的价值从来都不是性能,而是它 1) 为函数式的 UI 编程方式打开了大门;2) 可以渲染到 DOM 以外的 backend,比如 ReactNative。 总结 以上这些比较,更多的是对于框架开发研究者提供一些参考。主流的框架 + 合理的优化,足以应对绝大部分应用的性能需求。如果是对性能有极致需求的特殊情况,其实应该牺牲一些可维护性采取手动优化:比如 Atom 编辑器在文件渲染的实现上放弃了 React 而采用了自己实现的 tile-based rendering;又比如在移动端需要 DOM-pooling 的虚拟滚动,不需要考虑顺序变化,可以绕过框架的内置实现自己搞一个。

九旬 2020-05-24 11:46:45 0 浏览量 回答数 0

问题

E-MapReduce表管理是什么?

nicenelly 2019-12-01 21:17:33 1230 浏览量 回答数 0

问题

E-MapReduce表管理是什么?

nicenelly 2019-12-01 21:22:15 916 浏览量 回答数 0

问题

Windows服务器日常维护策略

我的中国 2019-12-01 21:57:39 2665 浏览量 回答数 1

问题

【精品问答】Python二级考试题库

珍宝珠 2019-12-01 22:03:38 1146 浏览量 回答数 2

回答

我不是Java开发人员,以下内容希望对您自己或其他可以在Java中提供更简洁语法的人有所帮助。 首先,我们应确定与您的价值有关的数据序列化的不同层次: 这是一个外部XML元素,因此第一步是将该值解释为XML片段并提取XML值。 之所以在此顶层使用XML反序列化,而不仅仅是使用字符串位置,是因为内部值可能已被 XML转义,因此我们需要使用XML编码规则来解析内部值。这给我们留下了strimg值: registerProfile|.|D|D|B95||43|5000|43100||UBSROOT43|NA|BMP|508|{"biometrics":{"fingerprints":{"fingerprints":[{"position":"RIGHT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEAAAAAADYAAAA="}},{"position":"LEFT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEADoAAAA"}}]}}} 下一级别是管道定界的,与CSV相同,除了转义字符是a |并且通常没有其他编码规则,因为|这不属于常规词法域的一部分,我们不需要任何进一步的转义。 因此,您可以将此字符串拆分为一个数组。 我们感兴趣的值是数组中的第15个元素,您可以事先知道,也可以简单地遍历这些元素以找到第一个以 {留下一个JSON值: {"biometrics":{"fingerprints":{"fingerprints":[{"position":"RIGHT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEAAAAAADYAAAA="}},{"position":"LEFT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEADoAAAA"}}]}}} 既然我们已经以JSON格式隔离了内部值,接下来要做的通常的事情就是将该值反序列化为一个对象。 我知道OP正在请求数组,但是如果我们真的想使用正确的工具,就可以将JSON对象实现为数组。 在C#中,上面的过程非常简单,我确定它也应该在Java中,但是我的尝试不断抛出错误。 因此,让我们假设(我知道... Ass-U-Me ...)在管道分隔的数组中只有一个JSON值,有了这个知识,我们可以使用以下方法隔离JSONint String.IndexOf(str) String xml = "<MSG>registerProfile|.|D|D|B95||43|5000|43100||UBSROOT43|NA|BMP|508|{\"biometrics\":{\"fingerprints\":{\"fingerprints\":[{\"position\":\"RIGHT_INDEX\",\"image\":{\"format\":\"BMP\",\"resolutionDpi\":\"508\",\"data\":\"Qk12WQEAAAAAADYAAAA=\"}},{\"position\":\"LEFT_INDEX\",\"image\":{\"format\":\"BMP\",\"resolutionDpi\":\"508\",\"data\":\"Qk12WQEADoAAAA\"}}]}}}</MSG>"; int start = xml.indexOf('{'); int end = xml.lastIndexOf('}') + 1; // +1 because we want to include the last character, so we need the index after it String json = xml.substring(start, end); 结果是: {"biometrics":{"fingerprints":{"fingerprints":[{"position":"RIGHT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEAAAAAADYAAAA="}},{"position":"LEFT_INDEX","image":{"format":"BMP","resolutionDpi":"508","data":"Qk12WQEADoAAAA"}}]}}} 格式化为漂亮: { "biometrics": { "fingerprints": { "fingerprints": [ { "position": "RIGHT_INDEX", "image": { "format": "BMP", "resolutionDpi": "508", "data": "Qk12WQEAAAAAADYAAAA=" } }, { "position": "LEFT_INDEX", "image": { "format": "BMP", "resolutionDpi": "508", "data": "Qk12WQEADoAAAA" } } ] } } } 一种方法是创建一个与该JSON值匹配的类结构,然后我们可以简单地.fromJson()获取整个值,而让我们相约一半,因此我们只需要为将实际使用的数据定义内部类结构即可。 现在,从该结构中,我们可以看到有一个外部对象,该对象仅具有一个称为的单个属性biometrics,该值再次是一个具有单个属性的名为的对象fingerprints。该属性的值是另一个具有单个属性的对象,fingerprints但这次它具有数组值。 以下是Java的证明,我首先提供了一个使用序列化的示例(使用gson库),然后提供了仅使用simple-JSON库读取数组中值的类似实现。 在JDoodle.com上试用 MyClass.java import java.util.*; import java.lang.*; import java.io.*; //import javax.json.*; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import com.google.gson.Gson; public class MyClass { public static void main(String args[]) { String xml = "<MSG>registerProfile|.|D|D|B95||43|5000|43100||UBSROOT43|NA|BMP|508|{\"biometrics\":{\"fingerprints\":{\"fingerprints\":[{\"position\":\"RIGHT_INDEX\",\"image\":{\"format\":\"BMP\",\"resolutionDpi\":\"508\",\"data\":\"Qk12WQEAAAAAADYAAAA=\"}},{\"position\":\"LEFT_INDEX\",\"image\":{\"format\":\"BMP\",\"resolutionDpi\":\"508\",\"data\":\"Qk12WQEADoAAAA\"}}]}}}</MSG>"; int start = xml.indexOf('{'); int end = xml.lastIndexOf('}') + 1; // +1 because we want to include the last character, so we need the index after it String jsonString = xml.substring(start, end); JSONParser parser = new JSONParser(); Gson gson = new Gson(); try { // locate the fingerprints inner array using simple-JSON (org.apache.clerezza.ext:org.json.simple:0.4 ) JSONObject jsonRoot = (JSONObject) parser.parse(jsonString); JSONObject biometrics = (JSONObject)jsonRoot.get("biometrics"); JSONObject fpOuter = (JSONObject)biometrics.get("fingerprints"); JSONArray fingerprints = (JSONArray)fpOuter.get("fingerprints"); // Using de-serialization from gson (com.google.code.gson:gson:2.8.6) FingerPrint[] prints = new FingerPrint[fingerprints.size()]; for(int i = 0; i < fingerprints.size(); i ++) { JSONObject fpGeneric = (JSONObject)fingerprints.get(i); prints[i] = gson.fromJson(fpGeneric.toString(), FingerPrint.class); } // Call the FingerprintImage function using the FingerPrint objects System.out.print("FingerPrint Object Index: 0"); FingerprintImage(prints[0].image.format, prints[0].position, prints[0].image.data ); System.out.println(); System.out.print("FingerPrint Object Index: 1"); FingerprintImage(prints[1].image.format, prints[1].position, prints[1].image.data ); System.out.println(); // ALTERNATE Array Implementation (doesn't use gson) String[] format = new String[fingerprints.size()]; String[] position = new String[fingerprints.size()]; String[] data = new String[fingerprints.size()]; for(int i = 0; i < fingerprints.size(); i ++) { JSONObject fpGeneric = (JSONObject)fingerprints.get(i); position[i] = (String)fpGeneric.get("position"); JSONObject image = (JSONObject)fpGeneric.get("image"); format[i] = (String)image.get("format"); data[i] = (String)image.get("data"); } System.out.print("Generic Arrays Index: 0"); FingerprintImage(format[0], position[0], data[0] ); System.out.println(); System.out.print("Generic Arrays Index: 1"); FingerprintImage(format[1], position[1], data[1] ); System.out.println(); } catch (ParseException ignore) { } } public static void FingerprintImage(String format, String position, String data) { setFormat(format); setPosition(position); setData(data); } public static void setFormat(String format) { System.out.print(", Format=" + format); } public static void setPosition(String position) { System.out.print(", Position=" + position); } public static void setData(String data) { System.out.print(", Data=" + data); } } 指纹软件 public class FingerPrint { public String position; public FingerPrintImage image; } FingerPrintImage.java public class FingerPrintImage { public String format; public int resolutionsDpi; public String data; } 通常认为反序列化技术优于强制/手动解析,尤其是当我们需要传递对多个解析值的引用时。在上述示例中,通过简单地读取format,position并且data为单独的阵列,它们之间的关系已成为去耦合,通过我们的代码实现我们仍然可以一起使用它们,只要我们使用相同的数组索引,但结构不再限定值之间的关系。反序列化为类型化的结构可保留值之间的关系,并简化了传递彼此相关的值的任务。 更新 如果使用序列化,则可以将等效FingerPrint对象传递给需要它的任何方法,而不是分别传递相关的值,此外,您可以简单地传递整个FingerPrint对象数组。 public static void FingerprintImage(FingerPrint print) { setFormat(print.image.format); setPosition(print.position); setData(print.image.data); } 要FingerPrint批量处理多个对象,请将方法更改为接受数组:FingerPrint[] 您可以使用相同的技术来处理数组或每个数组Format,Postion以及Data,尽管这样做实在不明智。绕过多个数组并期望接收代码知道应该同步解释每个数组,也就是说,每个数组中的相同索引对应于相同的指纹,这种实现细节太模糊了,将导致为了维护正常的噩梦,学习和精通面向对象的概念以及创建用于传递相关数据元素的业务对象要好得多,而不是将所有内容打包到分离的数组中。 以下代码可以帮助您使用OPs 数组方法处理多个项目,但应突出说明为什么此习惯是不习惯的习惯: public static void FingerprintImage(String[] formats, String[] positions, String[] datas) { // now you must iterate each of the arrays using the same index // however as there are no restrictions on the arrays, for each array // and each index we should be checking that the array has not gone out // of length. } 从面向对象的角度来看,像这样通过多个数组会引起很多问题,首先,开发人员将只需要知道必须在每个数组中使用相同的索引来检索相关信息。下一个重要的问题是错误处理... 如果datas只有1个元素,但positions只有2个元素,那么1个data元素属于2个元素中的哪个?还是这表明data两者都应使用相同的符号? 还有许多其他问题,请考虑何时需要3个元素... 虽然您确实可以逃避看起来像是快捷方式的代码,但除非您完全了解自己在做什么,否则就不应该这样做记录相关代码,您将对潜在的后果负责。 回答来源:Stack Overflow

montos 2020-03-26 09:12:07 0 浏览量 回答数 0

问题

Android API兼容性指南

mqc 2019-12-01 21:00:01 2106 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 UserDisable.UserDisable错误 当您访问OSS遇到如下的UserDisable错误: <Code>UserDisable</Code> <Message>UserDisable</Message> 有以下两类原因: 欠费被禁 确认欠费方法:在OSS 管理控制台上打开费用中心,检查是否欠费。如果欠费,请及时充值。 说明 OSS欠费后,还可以正常使用24小时,24小时后禁止访问。 历史数据保留15天,15天后历史数据将被删除。 当您在消息中心看到阿里云OSS欠费提醒后,如下图所示,请及时充值,不会影响您的正常使用。 安全原因被禁 在OSS 管理控制台上打开消息中心,在右侧的安全消息中查看违规通知。违规的原因有很多,比如您使用OSS做私服,您的图片涉黄、涉暴等。 说明 如果您有账户处于被禁状态,请务必处理,重新申请新账户,无法保证正常使用。 RequestTimeTooSkewed.The difference between…错误 访问OSS遇到如下的RequestTimeTooSkewed错误: <Code>RequestTimeTooSkewed</Code> <Message>The difference between the request time and the current time is too large.</Message> 原因:您发送请求的时间与OSS收到请求的时间,间隔超出了15分钟,OSS从安全考虑认为该请求是无效的,返回上述错误。请检查发送请求设备的系统时间,并根据时区调整到正确时间。 您可能会有下面的疑问: 发送请求的机器或设备的系统时间,调整标准是什么呢? OSS的系统时间采用GMT时间,您的设备的系统时间,需要调整到GMT时间,或与其相对应的时区时间。GMT(Greenwich Mean Time)是零时区的区时,即世界标准时间。 例如,您访问OSS的设备系统配置是东八区,系统时间调整到比GMT早8小时。我国的标准时间—北京时间—就是东八区时间。如果您的系统时间是东八区,那么您的系统时间调整到北京时间即可。 Windows系统查看时区的方法: 通过控制面板 > 时钟、语言和区域 > 设置日期和时间,打开日期和时间,时区 栏的+08:00,表示您的设备时区是东八区。 Linux/Unix系统查看时区的方法: 请执行date -R查看时间和时区。下图中的 +0800,表示您的设备系统时区是东八区。 使用多个地域的OSS,比如杭州、新加坡、美国,时间同步有问题吗? 没有问题。每个地域的OSS都使用GMT时间,您发送请求的设备系统时间也是GMT时间。 InvalidAccessKeyId.The OSS Access Key Id…错误 访问OSS遇到如下的错误: <Code>InvalidAccessKeyId</Code> <Message>The OSS Access Key Id you provided does not exist in our records.</Message> 原因:您的AccessKeyID禁用或不存在。排查方法如下: 登录阿里云控制台的 AccessKey 管理,确认访问OSS使用的AccessKeyID存在且处于启用状态。 如果您的AccessKeyID处于禁用状态,请开启。 如果您的AccessKeyID不存在请创建,并使用新的AccessKeyID访问OSS。 AccessDenied.The bucket you are attempting to…错误 访问OSS遇到如下的错误: <Code>AccessDenied</Code> <Message>The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.</Message> 原因:您访问Bucket使用的Endpoint不正确,如果您需要了解Endpoint的详细信息,请参看OSS 基本概念。 怎么找到正确的Endpoint呢?如果SDK异常抛出如下的异常,或返回如下错误: <Error> <Code>AccessDenied</Code> <Message>The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.</Message> <RequestId>56EA****3EE6</RequestId> <HostId>my-oss-bucket-*****.aliyuncs.com</HostId> <Bucket>my-oss-bucket-***</Bucket> <Endpoint>oss-cn-****.aliyuncs.com</Endpoint> </Error> 其中Endpoint中的oss-cn-****.aliyuncs.com就是正确的Endpoint,请使用http://oss-cn-****.aliyuncs.com或https://oss-cn-****.aliyuncs.com作为Endpoint访问OSS。 如果错误中没有Endpoint,请登录OSS控制台,在Bucket管理中找到您访问的Bucket,单击进入Bucket概览页面。OSS域名中可以看到内网和外网域名。 外网域名是在公网上访问OSS使用的域名;内网域名是指在阿里云内部访问的OSS使用的域名。比如您在您的ECS上访问OSS,可以使用内网域名。 Endpoint是域名去掉Bucket部分,加上访问协议。例如上图中OSS的公网域名是oss-****.aliyuncs.com,它的公网Endpoint是http://oss-cn-****.aliyuncs.com;类似,内网Endpoint是http://oss-cn-****-internal.aliyuncs.com。 ImageDamage.The image file may be damaged错误 访问OSS遇到如下的错误: <Code>ImageDamage</Code> <Message>The image file may be damaged.</Message> 原因:说明图片文件有部分信息丢失或损坏,导致无法正常识别或处理。您可能会有一个疑问,某图片在本地用图片处理器可以打开,OSS处理报错。原因是,图片浏览器会对损坏的图片做些处理,OSS图片服务暂时没有这个操作。 AccessDenied.AccessDenied错误 访问OSS遇到如下的错误: <Code>AccessDenied</Code> <Message>AccessDenied</Message> 原因:说明访问OSS的用户没有当前操作的权限。请确认使用的AccessKeyID/AccessKeySecret是正确的。如果使用的是子帐号/临时账户(STS),请确认当前用户的权限。确认方法: 在访问控制管理控制台单击用户管理,单击需要确认权限的用户,单击用户授权策略 > 加入组的授权策略查看该用户的权限,确认是否已经赋予当前用户Bucket/Object的操作权限。 SignatureDoesNotMatch.The request signature we calculated…错误 访问OSS遇到如下的错误: <Code>SignatureDoesNotMatch</Code> <Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message> 请按照以下步骤排查: 检查endpoint 请检查endpoint前面没有Bucket,后面没有多余的/,前后没有多余的空格。比如下面的endpoint是不合法的,http://my-bucket.oss-cn-hangzhou.aliyuncs.com、http://oss-cn-hangzhou.aliyuncs.com/、而 http:// oss-cn-hangzhou.aliyuncs.com 或 https:// oss-cn-hangzhou.aliyuncs.com是合法域名。 检查AccessKeyID/AccessKeySecret 请确认AccessKeyID/AccessKeySecret正确,确保AccessKeyID/AccessKeySecret前后都没有空格,特别是使用了复制粘贴的情况。 检查BucketName/ObjectKey 请确保BucketName/ObjectKey命名合法有效,符合要求。 Bucket命名规范:只能包括小写字母、数字和短横线(-),必须以小写字母或者数字开头,长度必须在3-63字节之间。 Object的命名规范:使用UTF-8编码,长度必须在1-1023字节之间,不能以“/”或者“\”字符开头。 如果是您自己实现的签名,请使用OSS SDK提供的签名方法。 OSS SDK提供了URL/Header签名的实现,详细请参看SDK文档。 如果您的环境不适合使用SDK,需要自己实现签名,签名方法请参考用户签名验证,仔细检查每个签名字段。 OSS的论坛上提供了一个可视化签名的工具,请比较每个签名字段和最后的签名,签名工具地址。 如果您使用了代理,请检查代理服务器是否添加额外的Header。 其它错误 请根据SDK返回的错误码、错误信息判断原因,特别是错误信息会提示错误原因。如果怀疑错误跟网络环境有关,请使用ossprobe排查问题,ossprobe会给出可能的原因。

2019-12-01 23:13:40 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 UserDisable.UserDisable错误 当您访问OSS遇到如下的UserDisable错误: <Code>UserDisable</Code> <Message>UserDisable</Message> 有以下两类原因: 欠费被禁 确认欠费方法:在OSS 管理控制台上打开费用中心,检查是否欠费。如果欠费,请及时充值。 说明 OSS欠费后,还可以正常使用24小时,24小时后禁止访问。 历史数据保留15天,15天后历史数据将被删除。 当您在消息中心看到阿里云OSS欠费提醒后,如下图所示,请及时充值,不会影响您的正常使用。 安全原因被禁 在OSS 管理控制台上打开消息中心,在右侧的安全消息中查看违规通知。违规的原因有很多,比如您使用OSS做私服,您的图片涉黄、涉暴等。 说明 如果您有账户处于被禁状态,请务必处理,重新申请新账户,无法保证正常使用。 RequestTimeTooSkewed.The difference between…错误 访问OSS遇到如下的RequestTimeTooSkewed错误: <Code>RequestTimeTooSkewed</Code> <Message>The difference between the request time and the current time is too large.</Message> 原因:您发送请求的时间与OSS收到请求的时间,间隔超出了15分钟,OSS从安全考虑认为该请求是无效的,返回上述错误。请检查发送请求设备的系统时间,并根据时区调整到正确时间。 您可能会有下面的疑问: 发送请求的机器或设备的系统时间,调整标准是什么呢? OSS的系统时间采用GMT时间,您的设备的系统时间,需要调整到GMT时间,或与其相对应的时区时间。GMT(Greenwich Mean Time)是零时区的区时,即世界标准时间。 例如,您访问OSS的设备系统配置是东八区,系统时间调整到比GMT早8小时。我国的标准时间—北京时间—就是东八区时间。如果您的系统时间是东八区,那么您的系统时间调整到北京时间即可。 Windows系统查看时区的方法: 通过控制面板 > 时钟、语言和区域 > 设置日期和时间,打开日期和时间,时区 栏的+08:00,表示您的设备时区是东八区。 Linux/Unix系统查看时区的方法: 请执行date -R查看时间和时区。下图中的 +0800,表示您的设备系统时区是东八区。 使用多个地域的OSS,比如杭州、新加坡、美国,时间同步有问题吗? 没有问题。每个地域的OSS都使用GMT时间,您发送请求的设备系统时间也是GMT时间。 InvalidAccessKeyId.The OSS Access Key Id…错误 访问OSS遇到如下的错误: <Code>InvalidAccessKeyId</Code> <Message>The OSS Access Key Id you provided does not exist in our records.</Message> 原因:您的AccessKeyID禁用或不存在。排查方法如下: 登录阿里云控制台的 AccessKey 管理,确认访问OSS使用的AccessKeyID存在且处于启用状态。 如果您的AccessKeyID处于禁用状态,请开启。 如果您的AccessKeyID不存在请创建,并使用新的AccessKeyID访问OSS。 AccessDenied.The bucket you are attempting to…错误 访问OSS遇到如下的错误: <Code>AccessDenied</Code> <Message>The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.</Message> 原因:您访问Bucket使用的Endpoint不正确,如果您需要了解Endpoint的详细信息,请参看OSS 基本概念。 怎么找到正确的Endpoint呢?如果SDK异常抛出如下的异常,或返回如下错误: <Error> <Code>AccessDenied</Code> <Message>The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.</Message> <RequestId>56EA****3EE6</RequestId> <HostId>my-oss-bucket-*****.aliyuncs.com</HostId> <Bucket>my-oss-bucket-***</Bucket> <Endpoint>oss-cn-****.aliyuncs.com</Endpoint> </Error> 其中Endpoint中的oss-cn-****.aliyuncs.com就是正确的Endpoint,请使用http://oss-cn-****.aliyuncs.com或https://oss-cn-****.aliyuncs.com作为Endpoint访问OSS。 如果错误中没有Endpoint,请登录OSS控制台,在Bucket管理中找到您访问的Bucket,单击进入Bucket概览页面。OSS域名中可以看到内网和外网域名。 外网域名是在公网上访问OSS使用的域名;内网域名是指在阿里云内部访问的OSS使用的域名。比如您在您的ECS上访问OSS,可以使用内网域名。 Endpoint是域名去掉Bucket部分,加上访问协议。例如上图中OSS的公网域名是oss-****.aliyuncs.com,它的公网Endpoint是http://oss-cn-****.aliyuncs.com;类似,内网Endpoint是http://oss-cn-****-internal.aliyuncs.com。 ImageDamage.The image file may be damaged错误 访问OSS遇到如下的错误: <Code>ImageDamage</Code> <Message>The image file may be damaged.</Message> 原因:说明图片文件有部分信息丢失或损坏,导致无法正常识别或处理。您可能会有一个疑问,某图片在本地用图片处理器可以打开,OSS处理报错。原因是,图片浏览器会对损坏的图片做些处理,OSS图片服务暂时没有这个操作。 AccessDenied.AccessDenied错误 访问OSS遇到如下的错误: <Code>AccessDenied</Code> <Message>AccessDenied</Message> 原因:说明访问OSS的用户没有当前操作的权限。请确认使用的AccessKeyID/AccessKeySecret是正确的。如果使用的是子帐号/临时账户(STS),请确认当前用户的权限。确认方法: 在访问控制管理控制台单击用户管理,单击需要确认权限的用户,单击用户授权策略 > 加入组的授权策略查看该用户的权限,确认是否已经赋予当前用户Bucket/Object的操作权限。 SignatureDoesNotMatch.The request signature we calculated…错误 访问OSS遇到如下的错误: <Code>SignatureDoesNotMatch</Code> <Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message> 请按照以下步骤排查: 检查endpoint 请检查endpoint前面没有Bucket,后面没有多余的/,前后没有多余的空格。比如下面的endpoint是不合法的,http://my-bucket.oss-cn-hangzhou.aliyuncs.com、http://oss-cn-hangzhou.aliyuncs.com/、而 http:// oss-cn-hangzhou.aliyuncs.com 或 https:// oss-cn-hangzhou.aliyuncs.com是合法域名。 检查AccessKeyID/AccessKeySecret 请确认AccessKeyID/AccessKeySecret正确,确保AccessKeyID/AccessKeySecret前后都没有空格,特别是使用了复制粘贴的情况。 检查BucketName/ObjectKey 请确保BucketName/ObjectKey命名合法有效,符合要求。 Bucket命名规范:只能包括小写字母、数字和短横线(-),必须以小写字母或者数字开头,长度必须在3-63字节之间。 Object的命名规范:使用UTF-8编码,长度必须在1-1023字节之间,不能以“/”或者“\”字符开头。 如果是您自己实现的签名,请使用OSS SDK提供的签名方法。 OSS SDK提供了URL/Header签名的实现,详细请参看SDK文档。 如果您的环境不适合使用SDK,需要自己实现签名,签名方法请参考用户签名验证,仔细检查每个签名字段。 OSS的论坛上提供了一个可视化签名的工具,请比较每个签名字段和最后的签名,签名工具地址。 如果您使用了代理,请检查代理服务器是否添加额外的Header。 其它错误 请根据SDK返回的错误码、错误信息判断原因,特别是错误信息会提示错误原因。如果怀疑错误跟网络环境有关,请使用ossprobe排查问题,ossprobe会给出可能的原因。

2019-12-01 23:13:41 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 UserDisable.UserDisable错误 当您访问OSS遇到如下的UserDisable错误: <Code>UserDisable</Code> <Message>UserDisable</Message> 有以下两类原因: 欠费被禁 确认欠费方法:在OSS 管理控制台上打开费用中心,检查是否欠费。如果欠费,请及时充值。 说明 OSS欠费后,还可以正常使用24小时,24小时后禁止访问。 历史数据保留15天,15天后历史数据将被删除。 当您在消息中心看到阿里云OSS欠费提醒后,如下图所示,请及时充值,不会影响您的正常使用。 安全原因被禁 在OSS 管理控制台上打开消息中心,在右侧的安全消息中查看违规通知。违规的原因有很多,比如您使用OSS做私服,您的图片涉黄、涉暴等。 说明 如果您有账户处于被禁状态,请务必处理,重新申请新账户,无法保证正常使用。 RequestTimeTooSkewed.The difference between…错误 访问OSS遇到如下的RequestTimeTooSkewed错误: <Code>RequestTimeTooSkewed</Code> <Message>The difference between the request time and the current time is too large.</Message> 原因:您发送请求的时间与OSS收到请求的时间,间隔超出了15分钟,OSS从安全考虑认为该请求是无效的,返回上述错误。请检查发送请求设备的系统时间,并根据时区调整到正确时间。 您可能会有下面的疑问: 发送请求的机器或设备的系统时间,调整标准是什么呢? OSS的系统时间采用GMT时间,您的设备的系统时间,需要调整到GMT时间,或与其相对应的时区时间。GMT(Greenwich Mean Time)是零时区的区时,即世界标准时间。 例如,您访问OSS的设备系统配置是东八区,系统时间调整到比GMT早8小时。我国的标准时间—北京时间—就是东八区时间。如果您的系统时间是东八区,那么您的系统时间调整到北京时间即可。 Windows系统查看时区的方法: 通过控制面板 > 时钟、语言和区域 > 设置日期和时间,打开日期和时间,时区 栏的+08:00,表示您的设备时区是东八区。 Linux/Unix系统查看时区的方法: 请执行date -R查看时间和时区。下图中的 +0800,表示您的设备系统时区是东八区。 使用多个地域的OSS,比如杭州、新加坡、美国,时间同步有问题吗? 没有问题。每个地域的OSS都使用GMT时间,您发送请求的设备系统时间也是GMT时间。 InvalidAccessKeyId.The OSS Access Key Id…错误 访问OSS遇到如下的错误: <Code>InvalidAccessKeyId</Code> <Message>The OSS Access Key Id you provided does not exist in our records.</Message> 原因:您的AccessKeyID禁用或不存在。排查方法如下: 登录阿里云控制台的 AccessKey 管理,确认访问OSS使用的AccessKeyID存在且处于启用状态。 如果您的AccessKeyID处于禁用状态,请开启。 如果您的AccessKeyID不存在请创建,并使用新的AccessKeyID访问OSS。 AccessDenied.The bucket you are attempting to…错误 访问OSS遇到如下的错误: <Code>AccessDenied</Code> <Message>The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.</Message> 原因:您访问Bucket使用的Endpoint不正确,如果您需要了解Endpoint的详细信息,请参看OSS 基本概念。 怎么找到正确的Endpoint呢?如果SDK异常抛出如下的异常,或返回如下错误: <Error> <Code>AccessDenied</Code> <Message>The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.</Message> <RequestId>56EA****3EE6</RequestId> <HostId>my-oss-bucket-*****.aliyuncs.com</HostId> <Bucket>my-oss-bucket-***</Bucket> <Endpoint>oss-cn-****.aliyuncs.com</Endpoint> </Error> 其中Endpoint中的oss-cn-****.aliyuncs.com就是正确的Endpoint,请使用http://oss-cn-****.aliyuncs.com或https://oss-cn-****.aliyuncs.com作为Endpoint访问OSS。 如果错误中没有Endpoint,请登录OSS控制台,在Bucket管理中找到您访问的Bucket,单击进入Bucket概览页面。OSS域名中可以看到内网和外网域名。 外网域名是在公网上访问OSS使用的域名;内网域名是指在阿里云内部访问的OSS使用的域名。比如您在您的ECS上访问OSS,可以使用内网域名。 Endpoint是域名去掉Bucket部分,加上访问协议。例如上图中OSS的公网域名是oss-****.aliyuncs.com,它的公网Endpoint是http://oss-cn-****.aliyuncs.com;类似,内网Endpoint是http://oss-cn-****-internal.aliyuncs.com。 ImageDamage.The image file may be damaged错误 访问OSS遇到如下的错误: <Code>ImageDamage</Code> <Message>The image file may be damaged.</Message> 原因:说明图片文件有部分信息丢失或损坏,导致无法正常识别或处理。您可能会有一个疑问,某图片在本地用图片处理器可以打开,OSS处理报错。原因是,图片浏览器会对损坏的图片做些处理,OSS图片服务暂时没有这个操作。 AccessDenied.AccessDenied错误 访问OSS遇到如下的错误: <Code>AccessDenied</Code> <Message>AccessDenied</Message> 原因:说明访问OSS的用户没有当前操作的权限。请确认使用的AccessKeyID/AccessKeySecret是正确的。如果使用的是子帐号/临时账户(STS),请确认当前用户的权限。确认方法: 在访问控制管理控制台单击用户管理,单击需要确认权限的用户,单击用户授权策略 > 加入组的授权策略查看该用户的权限,确认是否已经赋予当前用户Bucket/Object的操作权限。 SignatureDoesNotMatch.The request signature we calculated…错误 访问OSS遇到如下的错误: <Code>SignatureDoesNotMatch</Code> <Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message> 请按照以下步骤排查: 检查endpoint 请检查endpoint前面没有Bucket,后面没有多余的/,前后没有多余的空格。比如下面的endpoint是不合法的,http://my-bucket.oss-cn-hangzhou.aliyuncs.com、http://oss-cn-hangzhou.aliyuncs.com/、而 http:// oss-cn-hangzhou.aliyuncs.com 或 https:// oss-cn-hangzhou.aliyuncs.com是合法域名。 检查AccessKeyID/AccessKeySecret 请确认AccessKeyID/AccessKeySecret正确,确保AccessKeyID/AccessKeySecret前后都没有空格,特别是使用了复制粘贴的情况。 检查BucketName/ObjectKey 请确保BucketName/ObjectKey命名合法有效,符合要求。 Bucket命名规范:只能包括小写字母、数字和短横线(-),必须以小写字母或者数字开头,长度必须在3-63字节之间。 Object的命名规范:使用UTF-8编码,长度必须在1-1023字节之间,不能以“/”或者“\”字符开头。 如果是您自己实现的签名,请使用OSS SDK提供的签名方法。 OSS SDK提供了URL/Header签名的实现,详细请参看SDK文档。 如果您的环境不适合使用SDK,需要自己实现签名,签名方法请参考用户签名验证,仔细检查每个签名字段。 OSS的论坛上提供了一个可视化签名的工具,请比较每个签名字段和最后的签名,签名工具地址。 如果您使用了代理,请检查代理服务器是否添加额外的Header。 其它错误 请根据SDK返回的错误码、错误信息判断原因,特别是错误信息会提示错误原因。如果怀疑错误跟网络环境有关,请使用ossprobe排查问题,ossprobe会给出可能的原因。

2019-12-01 23:13:41 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档 UserDisable.UserDisable错误 当您访问OSS遇到如下的UserDisable错误: <Code>UserDisable</Code> <Message>UserDisable</Message> 有以下两类原因: 欠费被禁 确认欠费方法:在OSS 管理控制台上打开费用中心,检查是否欠费。如果欠费,请及时充值。 说明 OSS欠费后,还可以正常使用24小时,24小时后禁止访问。 历史数据保留15天,15天后历史数据将被删除。 当您在消息中心看到阿里云OSS欠费提醒后,如下图所示,请及时充值,不会影响您的正常使用。 安全原因被禁 在OSS 管理控制台上打开消息中心,在右侧的安全消息中查看违规通知。违规的原因有很多,比如您使用OSS做私服,您的图片涉黄、涉暴等。 说明 如果您有账户处于被禁状态,请务必处理,重新申请新账户,无法保证正常使用。 RequestTimeTooSkewed.The difference between…错误 访问OSS遇到如下的RequestTimeTooSkewed错误: <Code>RequestTimeTooSkewed</Code> <Message>The difference between the request time and the current time is too large.</Message> 原因:您发送请求的时间与OSS收到请求的时间,间隔超出了15分钟,OSS从安全考虑认为该请求是无效的,返回上述错误。请检查发送请求设备的系统时间,并根据时区调整到正确时间。 您可能会有下面的疑问: 发送请求的机器或设备的系统时间,调整标准是什么呢? OSS的系统时间采用GMT时间,您的设备的系统时间,需要调整到GMT时间,或与其相对应的时区时间。GMT(Greenwich Mean Time)是零时区的区时,即世界标准时间。 例如,您访问OSS的设备系统配置是东八区,系统时间调整到比GMT早8小时。我国的标准时间—北京时间—就是东八区时间。如果您的系统时间是东八区,那么您的系统时间调整到北京时间即可。 Windows系统查看时区的方法: 通过控制面板 > 时钟、语言和区域 > 设置日期和时间,打开日期和时间,时区 栏的+08:00,表示您的设备时区是东八区。 Linux/Unix系统查看时区的方法: 请执行date -R查看时间和时区。下图中的 +0800,表示您的设备系统时区是东八区。 使用多个地域的OSS,比如杭州、新加坡、美国,时间同步有问题吗? 没有问题。每个地域的OSS都使用GMT时间,您发送请求的设备系统时间也是GMT时间。 InvalidAccessKeyId.The OSS Access Key Id…错误 访问OSS遇到如下的错误: <Code>InvalidAccessKeyId</Code> <Message>The OSS Access Key Id you provided does not exist in our records.</Message> 原因:您的AccessKeyID禁用或不存在。排查方法如下: 登录阿里云控制台的 AccessKey 管理,确认访问OSS使用的AccessKeyID存在且处于启用状态。 如果您的AccessKeyID处于禁用状态,请开启。 如果您的AccessKeyID不存在请创建,并使用新的AccessKeyID访问OSS。 AccessDenied.The bucket you are attempting to…错误 访问OSS遇到如下的错误: <Code>AccessDenied</Code> <Message>The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.</Message> 原因:您访问Bucket使用的Endpoint不正确,如果您需要了解Endpoint的详细信息,请参看OSS 基本概念。 怎么找到正确的Endpoint呢?如果SDK异常抛出如下的异常,或返回如下错误: <Error> <Code>AccessDenied</Code> <Message>The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.</Message> <RequestId>56EA****3EE6</RequestId> <HostId>my-oss-bucket-*****.aliyuncs.com</HostId> <Bucket>my-oss-bucket-***</Bucket> <Endpoint>oss-cn-****.aliyuncs.com</Endpoint> </Error> 其中Endpoint中的oss-cn-****.aliyuncs.com就是正确的Endpoint,请使用http://oss-cn-****.aliyuncs.com或https://oss-cn-****.aliyuncs.com作为Endpoint访问OSS。 如果错误中没有Endpoint,请登录OSS控制台,在Bucket管理中找到您访问的Bucket,单击进入Bucket概览页面。OSS域名中可以看到内网和外网域名。 外网域名是在公网上访问OSS使用的域名;内网域名是指在阿里云内部访问的OSS使用的域名。比如您在您的ECS上访问OSS,可以使用内网域名。 Endpoint是域名去掉Bucket部分,加上访问协议。例如上图中OSS的公网域名是oss-****.aliyuncs.com,它的公网Endpoint是http://oss-cn-****.aliyuncs.com;类似,内网Endpoint是http://oss-cn-****-internal.aliyuncs.com。 ImageDamage.The image file may be damaged错误 访问OSS遇到如下的错误: <Code>ImageDamage</Code> <Message>The image file may be damaged.</Message> 原因:说明图片文件有部分信息丢失或损坏,导致无法正常识别或处理。您可能会有一个疑问,某图片在本地用图片处理器可以打开,OSS处理报错。原因是,图片浏览器会对损坏的图片做些处理,OSS图片服务暂时没有这个操作。 AccessDenied.AccessDenied错误 访问OSS遇到如下的错误: <Code>AccessDenied</Code> <Message>AccessDenied</Message> 原因:说明访问OSS的用户没有当前操作的权限。请确认使用的AccessKeyID/AccessKeySecret是正确的。如果使用的是子帐号/临时账户(STS),请确认当前用户的权限。确认方法: 在访问控制管理控制台单击用户管理,单击需要确认权限的用户,单击用户授权策略 > 加入组的授权策略查看该用户的权限,确认是否已经赋予当前用户Bucket/Object的操作权限。 SignatureDoesNotMatch.The request signature we calculated…错误 访问OSS遇到如下的错误: <Code>SignatureDoesNotMatch</Code> <Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message> 请按照以下步骤排查: 检查endpoint 请检查endpoint前面没有Bucket,后面没有多余的/,前后没有多余的空格。比如下面的endpoint是不合法的,http://my-bucket.oss-cn-hangzhou.aliyuncs.com、http://oss-cn-hangzhou.aliyuncs.com/、而 http:// oss-cn-hangzhou.aliyuncs.com 或 https:// oss-cn-hangzhou.aliyuncs.com是合法域名。 检查AccessKeyID/AccessKeySecret 请确认AccessKeyID/AccessKeySecret正确,确保AccessKeyID/AccessKeySecret前后都没有空格,特别是使用了复制粘贴的情况。 检查BucketName/ObjectKey 请确保BucketName/ObjectKey命名合法有效,符合要求。 Bucket命名规范:只能包括小写字母、数字和短横线(-),必须以小写字母或者数字开头,长度必须在3-63字节之间。 Object的命名规范:使用UTF-8编码,长度必须在1-1023字节之间,不能以“/”或者“\”字符开头。 如果是您自己实现的签名,请使用OSS SDK提供的签名方法。 OSS SDK提供了URL/Header签名的实现,详细请参看SDK文档。 如果您的环境不适合使用SDK,需要自己实现签名,签名方法请参考用户签名验证,仔细检查每个签名字段。 OSS的论坛上提供了一个可视化签名的工具,请比较每个签名字段和最后的签名,签名工具地址。 如果您使用了代理,请检查代理服务器是否添加额外的Header。 其它错误 请根据SDK返回的错误码、错误信息判断原因,特别是错误信息会提示错误原因。如果怀疑错误跟网络环境有关,请使用ossprobe排查问题,ossprobe会给出可能的原因。

2019-12-01 23:13:41 0 浏览量 回答数 0

回答

一、接口的默认方法 Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法,示例如下: interface Formula { double calculate(int a); default double sqrt(int a) { return Math.sqrt(a); } } Formula接口在拥有calculate方法之外同时还定义了sqrt方法,实现了Formula接口的子类只需要实现一个calculate方法,默认方法sqrt将在子类上可以直接使用。 Formula formula = new Formula() { @Override public double calculate(int a) { return sqrt(a * 100); } }; formula.calculate(100); // 100.0 formula.sqrt(16); // 4.0 文中的formula被实现为一个匿名类的实例,该代码非常容易理解,6行代码实现了计算 sqrt(a * 100)。在下一节中,我们将会看到实现单方法接口的更简单的做法。 译者注: 在Java中只有单继承,如果要让一个类赋予新的特性,通常是使用接口来实现,在C++中支持多继承,允许一个子类同时具有多个父类的接口与功能,在其他语言中,让一个类同时具有其他的可复用代码的方法叫做mixin。新的Java 8 的这个特新在编译器实现的角度上来说更加接近Scala的trait。 在C#中也有名为扩展方法的概念,允许给已存在的类型扩展方法,和Java 8的这个在语义上有差别。 二、Lambda 表达式 首先看看在老版本的Java中是如何排列字符串的: List<String> names = Arrays.asList("peter", "anna", "mike", "xenia"); Collections.sort(names, new Comparator<String>() { @Override public int compare(String a, String b) { return b.compareTo(a); } }); 只需要给静态方法 Collections.sort 传入一个List对象以及一个比较器来按指定顺序排列。通常做法都是创建一个匿名的比较器对象然后将其传递给sort方法。 在Java 8 中你就没必要使用这种传统的匿名对象的方式了,Java 8提供了更简洁的语法,lambda表达式: Collections.sort(names, (String a, String b) -> { return b.compareTo(a); }); 看到了吧,代码变得更段且更具有可读性,但是实际上还可以写得更短: Collections.sort(names, (String a, String b) -> b.compareTo(a)); 对于函数体只有一行代码的,你可以去掉大括号{}以及return关键字,但是你还可以写得更短点: Collections.sort(names, (a, b) -> b.compareTo(a)); Java编译器可以自动推导出参数类型,所以你可以不用再写一次类型。接下来我们看看lambda表达式还能作出什么更方便的东西来 三、函数式接口 Lambda表达式是如何在java的类型系统中表示的呢?每一个lambda表达式都对应一个类型,通常是接口类型。而“函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。因为 默认方法 不算抽象方法,所以你也可以给你的函数式接口添加默认方法。 我们可以将lambda表达式当作任意只包含一个抽象方法的接口类型,确保你的接口一定达到这个要求,你只需要给你的接口添加 @FunctionalInterface 注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。 @FunctionalInterface interface Converter<F, T> { T convert(F from); } Converter<String, Integer> converter = (from) -> Integer.valueOf(from); Integer converted = converter.convert("123"); System.out.println(converted); // 123 需要注意如果@FunctionalInterface如果没有指定,上面的代码也是对的。 译者注 将lambda表达式映射到一个单方法的接口上,这种做法在Java 8之前就有别的语言实现,比如Rhino JavaScript解释器,如果一个函数参数接收一个单方法的接口而你传递的是一个function,Rhino 解释器会自动做一个单接口的实例到function的适配器,典型的应用场景有 org.w3c.dom.events.EventTarget 的addEventListener 第二个参数 EventListener。 四、方法与构造函数引用 前一节中的代码还可以通过静态方法引用来表示: Converter<String, Integer> converter = Integer::valueOf; Integer converted = converter.convert("123"); System.out.println(converted); // 123 Java 8 允许你使用 :: 关键字来传递方法或者构造函数引用,上面的代码展示了如何引用一个静态方法,我们也可以引用一个对象的方法: converter = something::startsWith; String converted = converter.convert("Java"); System.out.println(converted); // "J" 接下来看看构造函数是如何使用::关键字来引用的,首先我们定义一个包含多个构造函数的简单类: class Person { String firstName; String lastName; Person() {} Person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } } 接下来我们指定一个用来创建Person对象的对象工厂接口: interface PersonFactory<P extends Person> { P create(String firstName, String lastName); } 这里我们使用构造函数引用来将他们关联起来,而不是实现一个完整的工厂: PersonFactory<Person> personFactory = Person::new; Person person = personFactory.create("Peter", "Parker"); 我们只需要使用 Person::new 来获取Person类构造函数的引用,Java编译器会自动根据PersonFactory.create方法的签名来选择合适的构造函数。 五、Lambda 作用域 在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。 六、访问局部变量 我们可以直接在lambda表达式中访问外层的局部变量: final int num = 1; Converter<Integer, String> stringConverter = (from) -> String.valueOf(from + num); stringConverter.convert(2); // 3 但是和匿名对象不同的是,这里的变量num可以不用声明为final,该代码同样正确: int num = 1; Converter<Integer, String> stringConverter = (from) -> String.valueOf(from + num); stringConverter.convert(2); // 3 不过这里的num必须不可被后面的代码修改(即隐性的具有final的语义),例如下面的就无法编译: int num = 1; Converter<Integer, String> stringConverter = (from) -> String.valueOf(from + num); num = 3; 在lambda表达式中试图修改num同样是不允许的。 七、访问对象字段与静态变量 和本地变量不同的是,lambda内部对于实例的字段以及静态变量是即可读又可写。该行为和匿名对象是一致的: class Lambda4 { static int outerStaticNum; int outerNum; void testScopes() { Converter<Integer, String> stringConverter1 = (from) -> { outerNum = 23; return String.valueOf(from); }; Converter<Integer, String> stringConverter2 = (from) -> { outerStaticNum = 72; return String.valueOf(from); }; } } 八、访问接口的默认方法 还记得第一节中的formula例子么,接口Formula定义了一个默认方法sqrt可以直接被formula的实例包括匿名对象访问到,但是在lambda表达式中这个是不行的。 Lambda表达式中是无法访问到默认方法的,以下代码将无法编译: Formula formula = (a) -> sqrt( a * 100); Built-in Functional Interfaces JDK 1.8 API包含了很多内建的函数式接口,在老Java中常用到的比如Comparator或者Runnable接口,这些接口都增加了@FunctionalInterface注解以便能用在lambda上。 Java 8 API同样还提供了很多全新的函数式接口来让工作更加方便,有一些接口是来自Google Guava库里的,即便你对这些很熟悉了,还是有必要看看这些是如何扩展到lambda上使用的。 Predicate接口 Predicate 接口只有一个参数,返回boolean类型。该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非): Predicate<String> predicate = (s) -> s.length() > 0; predicate.test("foo"); // true predicate.negate().test("foo"); // false Predicate<Boolean> nonNull = Objects::nonNull; Predicate<Boolean> isNull = Objects::isNull; Predicate<String> isEmpty = String::isEmpty; Predicate<String> isNotEmpty = isEmpty.negate(); Function 接口 Function 接口有一个参数并且返回一个结果,并附带了一些可以和其他函数组合的默认方法(compose, andThen): Function<String, Integer> toInteger = Integer::valueOf; Function<String, String> backToString = toInteger.andThen(String::valueOf); backToString.apply("123"); // "123" Supplier 接口 Supplier 接口返回一个任意范型的值,和Function接口不同的是该接口没有任何参数 Supplier personSupplier = Person::new; personSupplier.get(); // new Person Consumer 接口 Consumer 接口表示执行在单个参数上的操作。 Consumer greeter = (p) -> System.out.println("Hello, " + p.firstName); greeter.accept(new Person("Luke", "Skywalker")); Comparator 接口 Comparator 是老Java中的经典接口, Java 8在此之上添加了多种默认方法: Comparator comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName); Person p1 = new Person("John", "Doe"); Person p2 = new Person("Alice", "Wonderland"); comparator.compare(p1, p2); // > 0 comparator.reversed().compare(p1, p2); // < 0 Optional 接口 Optional 不是函数是接口,这是个用来防止NullPointerException异常的辅助类型,这是下一届中将要用到的重要概念,现在先简单的看看这个接口能干什么: Optional 被定义为一个简单的容器,其值可能是null或者不是null。在Java 8之前一般某个函数应该返回非空对象但是偶尔却可能返回了null,而在Java 8中,不推荐你返回null而是返回Optional。 Optional optional = Optional.of("bam"); optional.isPresent(); // true optional.get(); // "bam" optional.orElse("fallback"); // "bam" optional.ifPresent((s) -> System.out.println(s.charAt(0))); // "b" Stream 接口 java.util.Stream 表示能应用在一组元素上一次执行的操作序列。Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,这样你就可以将多个操作依次串起来。Stream 的创建需要指定一个数据源,比如 java.util.Collection的子类,List或者Set, Map不支持。Stream的操作可以串行执行或者并行执行。 首先看看Stream是怎么用,首先创建实例代码的用到的数据List: List stringCollection = new ArrayList<>(); stringCollection.add("ddd2"); stringCollection.add("aaa2"); stringCollection.add("bbb1"); stringCollection.add("aaa1"); stringCollection.add("bbb3"); stringCollection.add("ccc"); stringCollection.add("bbb2"); stringCollection.add("ddd1"); Java 8扩展了集合类,可以通过 Collection.stream() 或者 Collection.parallelStream() 来创建一个Stream。下面几节将详细解释常用的Stream操作: Filter 过滤 过滤通过一个predicate接口来过滤并只保留符合条件的元素,该操作属于中间操作,所以我们可以在过滤后的结果来应用其他Stream操作(比如forEach)。forEach需要一个函数来对过滤后的元素依次执行。forEach是一个最终操作,所以我们不能在forEach之后来执行其他Stream操作。 stringCollection .stream() .filter((s) -> s.startsWith("a")) .forEach(System.out::println); // "aaa2", "aaa1" Sort 排序 排序是一个中间操作,返回的是排序好后的Stream。如果你不指定一个自定义的Comparator则会使用默认排序。 stringCollection .stream() .sorted() .filter((s) -> s.startsWith("a")) .forEach(System.out::println); // "aaa1", "aaa2" 需要注意的是,排序只创建了一个排列好后的Stream,而不会影响原有的数据源,排序之后原数据stringCollection是不会被修改的。 System.out.println(stringCollection); // ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1 Map 映射 中间操作map会将元素根据指定的Function接口来依次将元素转成另外的对象,下面的示例展示了将字符串转换为大写字符串。你也可以通过map来讲对象转换成其他类型,map返回的Stream类型是根据你map传递进去的函数的返回值决定的。 stringCollection .stream() .map(String::toUpperCase) .sorted((a, b) -> b.compareTo(a)) .forEach(System.out::println); // "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1" Match 匹配 Stream提供了多种匹配操作,允许检测指定的Predicate是否匹配整个Stream。所有的匹配操作都是最终操作,并返回一个boolean类型的值。 boolean anyStartsWithA = stringCollection .stream() .anyMatch((s) -> s.startsWith("a")); System.out.println(anyStartsWithA); // true boolean allStartsWithA = stringCollection .stream() .allMatch((s) -> s.startsWith("a")); System.out.println(allStartsWithA); // false boolean noneStartsWithZ = stringCollection .stream() .noneMatch((s) -> s.startsWith("z")); System.out.println(noneStartsWithZ); // true Count 计数 计数是一个最终操作,返回Stream中元素的个数,返回值类型是long。 long startsWithB = stringCollection .stream() .filter((s) -> s.startsWith("b")) .count(); System.out.println(startsWithB); // 3 Reduce 规约 这是一个最终操作,允许通过指定的函数来讲stream中的多个元素规约为一个元素,规越后的结果是通过Optional接口表示的: Optional reduced = stringCollection .stream() .sorted() .reduce((s1, s2) -> s1 + "#" + s2); reduced.ifPresent(System.out::println); // "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2" 并行Streams 前面提到过Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。 下面的例子展示了是如何通过并行Stream来提升性能: 首先我们创建一个没有重复元素的大表 int max = 1000000; List values = new ArrayList<>(max); for (int i = 0; i < max; i++) { UUID uuid = UUID.randomUUID(); values.add(uuid.toString()); } 然后我们计算一下排序这个Stream要耗时多久, 串行排序: long t0 = System.nanoTime(); long count = values.stream().sorted().count(); System.out.println(count); long t1 = System.nanoTime(); long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0); System.out.println(String.format("sequential sort took: %d ms", millis)); // 串行耗时: 899 ms 并行排序: long t0 = System.nanoTime(); long count = values.parallelStream().sorted().count(); System.out.println(count); long t1 = System.nanoTime(); long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0); System.out.println(String.format("parallel sort took: %d ms", millis)); // 并行排序耗时: 472 ms 上面两个代码几乎是一样的,但是并行版的快了50%之多,唯一需要做的改动就是将stream()改为parallelStream()。 Map 前面提到过,Map类型不支持stream,不过Map提供了一些新的有用的方法来处理一些日常任务。 Map<Integer, String> map = new HashMap<>(); for (int i = 0; i < 10; i++) { map.putIfAbsent(i, "val" + i); } map.forEach((id, val) -> System.out.println(val)); 以上代码很容易理解, putIfAbsent 不需要我们做额外的存在性检查,而forEach则接收一个Consumer接口来对map里的每一个键值对进行操作。 下面的例子展示了map上的其他有用的函数: map.computeIfPresent(3, (num, val) -> val + num); map.get(3); // val33 map.computeIfPresent(9, (num, val) -> null); map.containsKey(9); // false map.computeIfAbsent(23, num -> "val" + num); map.containsKey(23); // true map.computeIfAbsent(3, num -> "bam"); map.get(3); // val33 接下来展示如何在Map里删除一个键值全都匹配的项 map.remove(3, "val3"); map.get(3); // val33 map.remove(3, "val33"); map.get(3); // null 另外一个有用的方法 map.getOrDefault(42, "not found"); // not found 对Map的元素做合并也变得很容易了: map.merge(9, "val9", (value, newValue) -> value.concat(newValue)); map.get(9); // val9 map.merge(9, "concat", (value, newValue) -> value.concat(newValue)); map.get(9); // val9concat Merge做的事情是如果键名不存在则插入,否则则对原键对应的值做合并操作并重新插入到map中。 九、Date API Java 8 在包java.time下包含了一组全新的时间日期API。新的日期API和开源的Joda-Time库差不多,但又不完全一样,下面的例子展示了这组新API里最重要的一些部分: Clock 时钟 Clock类提供了访问当前日期和时间的方法,Clock是时区敏感的,可以用来取代 System.currentTimeMillis() 来获取当前的微秒数。某一个特定的时间点也可以使用Instant类来表示,Instant类也可以用来创建老的java.util.Date对象。 Clock clock = Clock.systemDefaultZone(); long millis = clock.millis(); Instant instant = clock.instant(); Date legacyDate = Date.from(instant); // legacy java.util.Date Timezones 时区 在新API中时区使用ZoneId来表示。时区可以很方便的使用静态方法of来获取到。 时区定义了到UTS时间的时间差,在Instant时间点对象到本地日期对象之间转换的时候是极其重要的。 System.out.println(ZoneId.getAvailableZoneIds()); // prints all available timezone ids ZoneId zone1 = ZoneId.of("Europe/Berlin"); ZoneId zone2 = ZoneId.of("Brazil/East"); System.out.println(zone1.getRules()); System.out.println(zone2.getRules()); // ZoneRules[currentStandardOffset=+01:00] // ZoneRules[currentStandardOffset=-03:00] LocalTime 本地时间 LocalTime 定义了一个没有时区信息的时间,例如 晚上10点,或者 17:30:15。下面的例子使用前面代码创建的时区创建了两个本地时间。之后比较时间并以小时和分钟为单位计算两个时间的时间差: LocalTime now1 = LocalTime.now(zone1); LocalTime now2 = LocalTime.now(zone2); System.out.println(now1.isBefore(now2)); // false long hoursBetween = ChronoUnit.HOURS.between(now1, now2); long minutesBetween = ChronoUnit.MINUTES.between(now1, now2); System.out.println(hoursBetween); // -3 System.out.println(minutesBetween); // -239 LocalTime 提供了多种工厂方法来简化对象的创建,包括解析时间字符串。 LocalTime late = LocalTime.of(23, 59, 59); System.out.println(late); // 23:59:59 DateTimeFormatter germanFormatter = DateTimeFormatter .ofLocalizedTime(FormatStyle.SHORT) .withLocale(Locale.GERMAN); LocalTime leetTime = LocalTime.parse("13:37", germanFormatter); System.out.println(leetTime); // 13:37 LocalDate 本地日期 LocalDate 表示了一个确切的日期,比如 2014-03-11。该对象值是不可变的,用起来和LocalTime基本一致。下面的例子展示了如何给Date对象加减天/月/年。另外要注意的是这些对象是不可变的,操作返回的总是一个新实例。 LocalDate today = LocalDate.now(); LocalDate tomorrow = today.plus(1, ChronoUnit.DAYS); LocalDate yesterday = tomorrow.minusDays(2); LocalDate independenceDay = LocalDate.of(2014, Month.JULY, 4); DayOfWeek dayOfWeek = independenceDay.getDayOfWeek(); System.out.println(dayOfWeek); // FRIDAY 从字符串解析一个LocalDate类型和解析LocalTime一样简单: DateTimeFormatter germanFormatter = DateTimeFormatter .ofLocalizedDate(FormatStyle.MEDIUM) .withLocale(Locale.GERMAN); LocalDate xmas = LocalDate.parse("24.12.2014", germanFormatter); System.out.println(xmas); // 2014-12-24 LocalDateTime 本地日期时间 LocalDateTime 同时表示了时间和日期,相当于前两节内容合并到一个对象上了。LocalDateTime和LocalTime还有LocalDate一样,都是不可变的。LocalDateTime提供了一些能访问具体字段的方法。 LocalDateTime sylvester = LocalDateTime.of(2014, Month.DECEMBER, 31, 23, 59, 59); DayOfWeek dayOfWeek = sylvester.getDayOfWeek(); System.out.println(dayOfWeek); // WEDNESDAY Month month = sylvester.getMonth(); System.out.println(month); // DECEMBER long minuteOfDay = sylvester.getLong(ChronoField.MINUTE_OF_DAY); System.out.println(minuteOfDay); // 1439 只要附加上时区信息,就可以将其转换为一个时间点Instant对象,Instant时间点对象可以很容易的转换为老式的java.util.Date。 Instant instant = sylvester .atZone(ZoneId.systemDefault()) .toInstant(); Date legacyDate = Date.from(instant); System.out.println(legacyDate); // Wed Dec 31 23:59:59 CET 2014 格式化LocalDateTime和格式化时间和日期一样的,除了使用预定义好的格式外,我们也可以自己定义格式: DateTimeFormatter formatter = DateTimeFormatter .ofPattern("MMM dd, yyyy - HH:mm"); LocalDateTime parsed = LocalDateTime.parse("Nov 03, 2014 - 07:13", formatter); String string = formatter.format(parsed); System.out.println(string); // Nov 03, 2014 - 07:13 和java.text.NumberFormat不一样的是新版的DateTimeFormatter是不可变的,所以它是线程安全的。 关于时间日期格式的详细信息:http://download.java.net/jdk8/docs/api/java/time/format/DateTimeFormatter.html 十、Annotation 注解 在Java 8中支持多重注解了,先看个例子来理解一下是什么意思。 首先定义一个包装类Hints注解用来放置一组具体的Hint注解: @interface Hints { Hint[] value(); } @Repeatable(Hints.class) @interface Hint { String value(); } Java 8允许我们把同一个类型的注解使用多次,只需要给该注解标注一下@Repeatable即可。 例 1: 使用包装类当容器来存多个注解(老方法) @Hints({@Hint("hint1"), @Hint("hint2")}) class Person {} 例 2:使用多重注解(新方法) @Hint("hint1") @Hint("hint2") class Person {} 第二个例子里java编译器会隐性的帮你定义好@Hints注解,了解这一点有助于你用反射来获取这些信息: Hint hint = Person.class.getAnnotation(Hint.class); System.out.println(hint); // null Hints hints1 = Person.class.getAnnotation(Hints.class); System.out.println(hints1.value().length); // 2 Hint[] hints2 = Person.class.getAnnotationsByType(Hint.class); System.out.println(hints2.length); // 2 即便我们没有在Person类上定义@Hints注解,我们还是可以通过 getAnnotation(Hints.class) 来获取 @Hints注解,更加方便的方法是使用 getAnnotationsByType 可以直接获取到所有的@Hint注解。 另外Java 8的注解还增加到两种新的target上了: @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) @interface MyAnnotation {}

日你dady哟 2019-12-02 03:08:13 0 浏览量 回答数 0
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 企业信息查询 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 企业建站模板