自Java 13 以后,我们可以使用三引号来表示一个多行字符串,被官方称为“文本块”。文本块常用来表示多行的或大段的文字。例如:public class StringTest3 { public static void main(String[] args) { String str = """ Java 很棒! 慕课网很棒!! 能够在慕课网学 Java 更棒!!!"""; System.out.println(str); }}Tips:这里需要注意的是,文本块中起始的三引号后面要另起一行,也就是说下面这种写法是错误的:String str = """Java 很棒! 慕课网很棒!! 能够在慕课网学 Java 更棒!!!""";如果我们直接使用javac命令编译代码,将会报错:javac StringTest3.javaStringTest3.java:4: 错误: 文本块 是预览功能,默认情况下禁用。 String str = """ ^ (请使用 --enable-preview 以启用 文本块)1 个错误报错告诉我们:文本块是预览功能,默认是禁用的。我们可以给编译器加上一些参数来编译执行代码:$ javac -source 14 --enable-preview StringTest3.java$ java --enable-preview StringTest3Java 很棒!慕课网很棒!!能够在慕课网学 Java 更棒!!!
在 FTS 中,原始文本在构建索引之前需要被向量化。原始文本(如:字符串)必须先被向量化后才能通过 FTS 对其检索,向量化后的内容需要存储到一个单独的向量字段中,该向量的数据类型是tsvector。PostgreSQL 提供了to_tsvector函数来将原始文本向量化,如下:SELECT * FROM to_tsvector('jiebacfg','SQL,你敢吃我俺老孙一棒吗?'); to_tsvector------------------------------------------- 'sql':1 '一棒吗':9 '吃':5 '敢':4 '老孙':8tsvector是由(词,序列)元组组成的列表,如sql是原始文本中的第一个词,所以它的序列是1。
我们使用for循环连续打印5行”慕课网真棒“的字样,代码如下:488运行结果:慕课网真棒慕课网真棒慕课网真棒慕课网真棒慕课网真棒我们现在使用for来实现1到100的累加求和,代码如下:489运行结果:1到100的累加和为:5050程序解析:在执行循环体前,会先执行括号中的变量声明语句int i = 1,它定义了一个计数器变量i并且赋值为1(注意这个语句只执行一次)。然后会执行条件判断语句i <= 100,显然条件成立,执行循环体,循环体执行完成后会才会执行括号中的第三个语句i ++,再次判断条件是否成立,直到当i的值为100时,最后一次执行循环体,这个时候i再次自增1为101,条件不成立,结束循环。实际使用中,通常使用for循环来遍历一个数组,我们将在 Java 数组小节举例介绍。for循环中第一个语句,变量声明语句可以一次声明多个整型变量,实例代码如下:490运行结果:1 10 2 9 3 8 4 7 5 6 6 5 7 4 8 3 9 2 10 1另外,for循环还可以缺省变量声明语句、循环条件和迭代语句,实例:// 缺省变量声明语句for (int i = 0; ; i ++) { // 语句}// 缺省循环条件语句和迭代语句for (int i = 0; ; ) { // 语句}// 缺省所有语句for (;;) { // 语句}但请注意,通常情况下不建议这样写。
一般公司在开发时,可以使用 Swagger2 快速实现测试,并生成在线文档。由于开发阶段经常会修改接口,所以编写纸质文档实在是劳民伤财。如果使用 Swagger2 ,重启 Spring Boot 后刷新页面,就能看到最新 API 文档。还有一个小技巧,我们可以开启热部署。当我们的代码发生变化时, Spring Boot 会自动重启,这样就省得每次都要手工重启 Spring Boot 。实例: <!-- 引入该依赖即可开启热部署 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency>通过引入依赖,简单配置,就能实现一个非常棒的功能,这就是 Spring Boot 开箱即用的优点体现。
本节课程讲解 PO 对象的 3 种状态,以及 3 种状态之间的转化方式。了解处于持久化状态的 PO 具有持久化能力,这是 Hibernate 提供的一个很棒的 程序中对象与数据库数据自动同步的方案。也是一种快速开发方案。本节课区分了几个常用方法的差异性。但真相似乎就是:大家都和持久化状态有关系。
ECharts 提供了常规的折线图、柱状图、散点图、饼图、K线图,用于统计的盒形图,用于地理数据可视化的地图、热力图、线图,用于关系数据可视化的关系图、treemap、旭日图,多维数据可视化的平行坐标,还有用于 BI 的漏斗图,仪表盘,并且支持图与图之间的混搭。除了已经内置的包含了丰富功能的图表,ECharts 还提供了自定义系列,只需要传入一个_renderItem_函数,就可以从数据映射到任何你想要的图形,更棒的是这些都还能和已有的交互组件结合使用而不需要操心其它事情。你可以在下载界面下载包含所有图表的构建文件,如果只是需要其中一两个图表,又嫌包含所有图表的构建文件太大,也可以在在线构建中选择需要的图表类型后自定义构建。
前言:同学们大家好,在之前的课程中,给大家简单介绍了yarn的基本概念和命令使用方法。我们说,yarn是一个非常具有竞争力的依赖管理工具。甚至最近几年,它的热度一度超过传统工具npm。它简洁的日志输出方式,依赖管理方案,以及下载速度,都给开发者带来了非常棒的体验。下面我给大家用实际开发场景测试一下,具体说明yarn的优势。
mpvue 框架是一个很棒的小程序开发框架,由美团技术团队打造,18年上线的。当时一上线就获得了小程序界的广泛关注,因为 mpvue 无限接近 vue 开发,基本做到了从 Vue.js 到小程序的零成本切换。如果之前掌握了 Vue.js 语法,用 mpvue 框架开发小程序几乎不会增加新的学习成本,降低了开发小程序的门槛,所以受到很多开发者的欢迎。那我们为什么不继续使用 mpvue 框架,要将 mpvue 项目转成 uni-app 项目呢?这一小节主要讲解为什么要将 mpvue 项目转成 uni-app 项目以及如何将 mpvue 项目转换成 uni-app 项目。
但是有时候我想打印一个网页,比如你觉得这节教程写的非常棒,但是内容太多了一下子记不住,打算把它打印在纸上没事的时候就看看,打印出来以后你就会发现有这几个问题:样式有可能会乱打印出来很多没用的内容打印用了很多张纸因为纸张的大小一般就是A4,和电脑屏幕的比例可不一样,在电脑上看着正常的样式,换个比例可能就会乱。在电脑上有意义的东西可能在纸上就没意义了,比如那些按钮,点击返回上一页什么的,在电脑上可以点,在纸上就变成了一个占地儿的摆设。用户真正在意的,也就是那些想打印在纸上的这些文字内容,所以需要用 print 来检测是否为打印设备,是的话就不显示那些按钮啊、广告啊、视频啊等等那类的样式了,重点突出的是想打印在纸上的内容。
解析器是一种帮我们结构化网页内容的工具,通过解析器,我们可以得到结构化的数据,而不是单纯的字符,方便我们解析和查找数据。BeautifulSoup 的解析器有 html.parse,html5lib,lxml 等。BeautifulSoup 本身支持的标准库是 html.parse,html5lib。但是,lxml 的性能非常棒,以及拥有良好的容错能力,现在被广泛的使用。解析器对比:html.parse 是 Python 标准库的解析器,这个解析器执行速度不是太快,但是文档容错能力比较好。html.5lib 同样是内置的解析器,它是通过浏览器的方式解析数据,可以生成良好的 HTML5 格式的文档,但是速度比较慢。lxml 是第三方解析器,需要额外安装。这个解析器执行速度快,并且是唯一支持 XML 的解析器。在这里我们也会选用 lxml 来进行讲解。安装 lxml 和安装 BeautifulSoup 类似,同样只需一行命令就好:pip install lxml安装成功后,如下所示:
我们知道人类是通过语言进行沟通的。比如,帅哥 A 说:“慕课网的课程都很棒!”。而美女 B 是 imooc 迷,随声附和道:“嗯,确实!”。然而美女 C 完全不了解 imooc, 她可能默不作声,或者反问:“慕课网是什么?”。这意味着,人们的沟通是基于一定的前提假设的,是基于一些大家都能理解的、约定俗成的规定的。我们把这些约定或者规则叫做协议(Protocol)。两台计算机之间的通信也是模拟人类交流的,通信之前也需要有一些约定,也就是说要提前设计好协议。计算机网络协议的规模非常庞大,数据包的收发过程也非常复杂。为了使计算机网络容易理解、传播和实现,科学家们对网络进行了分层设计,并对其进行了标准化,最终形成了经典的 ISO/OSI 参考模型和 TCP/IP 参考模型。
事实上,可供我们选择的编辑器有很多种,比如 Sublime,VSCode,Atom,WebStorm,HBuilder 等等,现在我们就来简单对比一下比较常用的编辑器。Tips:数据因个人电脑,项目,版本等有关,仅供参考说明Sublime TextVS CodeAtomWebstormHbuilderNotepad++大小(M)10.454.717426618.33.86启动(s)0.10.2 ~ 0.30.2 ~ 0.30.3+0.2<= 0.1友好程度优秀优秀优秀良好良好优秀多开支持支持支持支持支持不支持是否收费收费但使用无限制免费免费收费免费免费功能性优秀优秀优秀优秀一般良好这里简要列举一些 Sublime 编辑器的优缺点优点:轻便,打开速度快,同时编辑几个项目都不会出现卡顿现象;插件市场丰富,编辑器功能强大;对开发者友好,开发体验超级棒。缺点:可以无限期使用,但是偶尔会出现收费弹框,关掉即可;包管理器需要自行安装,不能科学上网需要设置国内源。假如你喜欢轻便,打开速度快,有时候需要同时编辑多个项目,享受极致编程体验,那 Sublime 编辑器将是你的不二选择。另外 notepad 可以作为一个文本编辑器来辅助。VSCode,Atom 插件装多了的话可能略显臃肿,打开速度稍逊一些,但同样功能也是非常强大。Webstorm 收费,界面略微不好看。HBuilder 的插件市场一般,但是可以方便快速的开发跨平台的 app。总结:每个编辑器都有它自己的优缺点,适合自己的才是最好的。那么你选好自己的装备了吗?
以最常见的在网站注册新用户场景为例,如果经过了基本的业务逻辑之后,要通过短信和邮件的方式验证是否用户本人注册,每个流程的请求响应耗时为 100ms,在同步的方式下总共需要耗时 300ms。 (同步处理场景)其中发送验证短信以及发送验证邮件两个步骤并没有强制的先后依赖关系,所以同步请求的效率相对较低,使用消息队列可以将验证短信和邮件的模块拆开,经过消息队列中转分发请求,假设消息队列的读写时间为 20ms,总流程的耗时被优化到 220ms。 (消息队列异步处理场景)上述异步请求的过程本质上也是应用解耦的过程,最基础的应用架构中可以将短信注册模块和邮件注册模块都可以耦合在注册业务逻辑中,但是如果有其他的服务也需要使用短信注册功能,就只能调用注册业务的短信模块接口。此时,程序的鲁棒性相对较差,当注册业务模块的服务器宕机之后,会造成所有服务的短信模块都不可用,所以需要将短信模块解耦出来,同理,邮件模块也需要被拆分为单独的服务。候选人需要注意一点,这种拆分本质上都是为了应用服务的高可用。
面试官提问:RabbitMQ 如何保证消息不会被重复消费?题目解析:所有的消息队列都要保证同一条消息不会被重复消费,RabbitMQ 重复消费消息的可能场景主要有两种:(1)生产者重复发送消息:生产者在往消息队列发送消息时,发生了网络抖动,生产者没有收到确认信号,但是实际上消息队列已经收到了消息,超过一定时间后生产者会重新发送消息,这时一条消息被发送了两次;(2)消费者重复接受消息:消费者成功消费消息后,发生了网络抖动,消息队列没有收到确认信号,超过一段时间后会重新给消费者投递相同的消息,同一条消息即存在被消费两次的可能。通用解决方案是在消息实体中添加全局唯一的id,例如 msg_id(消息ID),在业务逻辑层保证消息的幂等性,具体参考步骤:(1)消费者在收到消息之后,根据 msg_id 从缓存/数据库中查询是否存在已有消息;(2)如果不存在已有消息,那么消费之后,将 msg_id 对应的消息实体或者序列化对象写入缓存/数据库;(3)如果存在已有消息,说明这条消息已被消费过,丢弃消息并且打一条告警日志。并且可以根据重复消费的容忍程度以及性能要求选择使用缓存还是使用数据库,如果对判断的速度要求高,可以使用 Redis 作为缓存;如果对判断的稳定性和鲁棒性要求高,使用数据库存储消息实体,同时将 msg_id 作为数据库表的唯一键,插入重复记录一定会抛出异常,避免数据库因为并发问题产生脏数据,保证了消息消费的不可重复性。
Button 的多状态变化是很常用也是效果非常棒的一个效果,它的可以最大化的增强互动感。通过 StateListDrawable 设置 Button 在不同状态下的样式效果,比如在按下、抬起、选中、无效等等不同状态下可以呈现不同的形状和颜色,这样可以给用户更多的点击反馈。StateListDrawable 用来记录各个状态列表,并通过 Drawable 的形式描述各个状态下要呈现的样式。它支持以下设置项:drawable: Button 的背景样式,搭配后面的状态使用表示当前状态下的样式。如果没有设置状态,则为默认样式state_pressed: 按下态state_enabled: 可用状态state_focused: 获得焦点状态state_window_focused: 获得窗口焦点状态state_checkable: 可选状态(针对 checkbox)state_checked: 勾选态state_selected: 选择态(针对滚轮的场景)state_active: 活动状态(针对 slidingTab)state_single: 包含多个子控件时,只显示一个子控件的状态state_first: 包含多个子控件时,第一个子控件处于显示状态state_middle: 包含多个子控件时,中间一个子控件处于显示状态state_last: 包含多个子控件时,最后一个子控件处于显示状态其中最常用就是前 3 个状态。我们新增一个 button_pressd_background.xml,内容如下:<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#DF866B" /> <corners android:bottomLeftRadius="50dp" android:bottomRightRadius="50dp" android:topLeftRadius="50dp" android:topRightRadius="50dp" /> <stroke android:width="3dp" android:color="#99CCFF" /></shape>我们在之前的样式上修改了定点的弧度及背景颜色,希望他在点击的时候能够变成新的样式,接下来还需要一个 StateListDrawable 文件。我们仍然在 drawable 目录下创建文件:button_selector.xml,代码如下:<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/button_pressd_background" android:state_pressed="true" /> <item android:drawable="@drawable/button_background" /></selector>这里采用<selector/>标签,直译过来就是“选择器”,即在不同状态下选择哪种样式。最后我们将 Button 的android:background属性指向 button_selector.xml 文件: android:background="@drawable/button_selector"大功告成,这时候只需要轻轻点击 Button,就会发现神奇的现象:这样是不是更有互动感?采用 StateListDrawable 还可以指定很多的状态变化,这里就留给大家去发明创造。
这是 leetcode 上算法部分第 455 题,为简单编程题。题目描述如下:你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 iii ,都有一个胃口值 $g_i $,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 jjj ,都有一个尺寸 sjs_jsj 。如果 $s_j >= g_i $,我们可以将这个饼干 jjj 分配给孩子 iii ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。注意:你可以假设胃口值为正。一个小朋友最多只能拥有一块饼干。示例1:输入: [1,2,3], [1,1]输出: 1解释: 你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。所以你应该输出1。示例2:输入: [1,2], [1,2,3]输出: 2解释: 你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。你拥有的饼干数量和尺寸都足以让所有孩子满足。所以你应该输出2。这里的解题思路也是非常清晰的:**同样也是贪心的思路,我们将孩子和饼干的胃口分别从小到大进行排序,从最小的饼干和第一个孩子开始。饼干指针一直向后执行,找到一个饼干满足孩子胃口,则孩子指针向后移动一位,同时满足的孩子数加1,如此执行直到孩子或者饼干的指针走完即可。**这样的一个尽可能最小饼干满足最小胃口的策略其实就是贪心思路。按照上面的思路,题解第一步就是对孩子的胃口和饼干分别进行排序,从小达到:g.sort()s.sort()接下来就是实现饼干满足小孩,我们分别给小孩的胃口数组、饼干数组设置初始化指针,然后初始化一个满足小孩数的变量:id1, id2, count = 0, 0, 0接下来就是遍历饼干数组和移动小孩胃口数组指针。如果饼干尺寸大于等于当前小孩胃口,则满足小孩,count 数加1,同时饼干和小孩胃口数组指针分别后移一位;如果饼干尺寸小于小孩胃口,则只有饼干指针后移一位。如此,直到最后饼干或者小孩的指针指到最后循环结束:# 循环,当其中一个列表扫描完毕后结束while id1 < len(g) and id2 < len(s): if g[id1] <= s[id2]: # 满足孩子,孩子指针+1,同时结果+1 id1 += 1 count += 1 # 饼干指针+1,无论是满足和不满足孩子,都要往后走一位 id2 += 1最后我们完整给出实现上述题解的方法,如下:def findContentChildren(g, s): # 使用贪心策略,先排序,最小胃口孩子对应最小能满足的饼干 g.sort() s.sort() id1, id2, count = 0, 0, 0 while id1 < len(g) and id2 < len(s): # 一次循环,当其中一个列表扫描完毕后结束 if g[id1] <= s[id2]: # 满足孩子,孩子指针+1,同时结果+1 id1 += 1 count += 1 # 饼干指针+1,无论是满足和不满足孩子,都要往后走一位 id2 += 1 return count
前面我们的配置都是将 order 模块的 build.config,单独拆各个模块来讲的。可能大家有点乱。下面我们看下完整的配置应该是怎样的。if (isRelease) { // 如果是发布版本时,各个模块都不能独立运行 apply plugin: 'com.android.library'} else { apply plugin: 'com.android.application'}def rootAndroidId = rootProject.ext.androidIddef appId = rootProject.ext.appIddef support = rootProject.ext.dependenciesandroid { compileSdkVersion rootAndroidId.compileSdkVersion buildToolsVersion rootAndroidId.buildToolsVersion defaultConfig { if (!isRelease) { // 如果是集成化模式,不能有 applicationId applicationId appId.order // 组件化模式能独立运行才能有 applicationId } minSdkVersion rootAndroidId.minSdkVersion targetSdkVersion rootAndroidId.targetSdkVersion versionCode rootAndroidId.versionCode versionName rootAndroidId.versionName testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" buildConfigField("boolean", "isRelease", String.valueOf(isRelease)) } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } // 配置资源路径 sourceSets { main { if (!isRelease) { // 如果是组件化模式,需要单独运行时 manifest.srcFile 'src/main/debug/AndroidManifest.xml' } else { // 集成化模式,整个项目打包apk manifest.srcFile 'src/main/AndroidManifest.xml' java { // release 时 debug 目录下文件不需要合并到主工程 exclude '**/debug/**' } } } }}dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) // 循环引入第三方库 support.each { k, v -> implementation v } implementation project(':common') // 公共基础库}
我们在之前的章节讲了 Ruby 的很多对象,学会了如何使用简单的对象(例如:数字和字符串)以及数据结构数组和哈希来完成一些工作,了解如何使用方法,做好了充足的准备。本章中,我会为大家讲解 Ruby 的类,如何创建一个类以及类的实例,以及类的实例方法如何创建。
块是 Ruby 程序员最喜欢的东西之一。它是一项非常强大的功能,使我们能够编写非常灵活的代码,拥有极高的可读性,并且可以在各处使用。本章中我们会详细为您讲解块的使用。
在上一个小节中讲解了 RESTful 架构的概念,本节通过具体的实例加深对 RESTful 架构的理解。
在左侧的最上方,可以搜索自己想要查看的节点,这里是支持正则表达式的。
监控是管理基础设施的核心工具。没有监控,我们将无法了解系统环境、进行诊断故障、制定容量计划,最糟的就是,故障发生了也不会被发现。从技术角度来看,监控是衡量和管理技术系统的工具和流程。监控将系统和应用程序生成的指标转换为对应的业务价值。监控系统需要在基于容器的微服务中自动且快速地识别生命周期,并持续地提供实时的监控检测。在上一节中,我们已经使用WeaveScope搭建了一个容器监控管理系统,并带有一些基本的监控功能。但它对于自定义数据获取、自动告警、细化监控指标和展示的时候,生态、功能性和扩展性都有欠缺,系统及需求复杂时难以满足我们的定制化的监控需求。这时,我们就需要围绕Premetheus,配合其生态及相关工具,配置我们的监控平台。
直到本章为止,我们所做的所有工作都涉及到处理内存中的数据。既然我们已经涵盖了 Ruby 语言的所有基础知识,是时候将我们的注意力转向使用 Ruby 中的文件和目录了。本章中会对 Ruby 如何操作目录做具体介绍。
在之前的章节中,我们学习了布尔对象、数字对象、字符串对象等,但是有的时候,我们需要将一组对象组合起来成为一个独立的对象,本章节让我们将学习 Ruby 数组,如何创建一个数组以及掌握其常用的实例方法。
我们在之前的章节中介绍了类,在本章节中,我会来介绍一下 Ruby 模块的概念以及如何去使用一个模块。
Ruby 的范围(Ranges)允许以范围的形式表示数据(换句话说,数据集具有开始和结束值以及介于两者之间的值的逻辑顺序)。范围内的值可以是数字,字符,字符串或对象。在本章中,我们将研究Ruby 支持的三种范围,即序列,条件和间隔。
本章节中会为大家介绍如何为类打一个补丁,拓展类的方法以及了解“猴子补丁“,如何避免“猴子补丁”。
AutoCompleteTextView 作为升级版的 EditText,要用到 API 的地方并不多,大多数场景还需要掌握属性的设置就行,这里对 API 做一个简单的讲解。getAdapter()返回一个 ListAdapter 类型的 adapter ,即我们代码中绑定的 adapter 对象。getCompletionHint()获取当前匹配的补全信息列表getDropDownAnchor()获取下拉补全列表的锚定 View 的 idgetListSelection()获取下拉列表中被选中的选项所在的位置isPopupShowing()判断下拉菜单是否弹出showDropDown()弹出下拉菜单
在上一节中,我们重点介绍了 Maven 的项目对象模型(POM),本节我们重点介绍另一个重要概念–依赖。我们会介绍什么是依赖,以及在我们平时的工作中的最佳实践。