米罗说
- 没有刻意练习就是混日子
- 不琢磨就是混日子
- 没有自学能力的人没有未来
- 学习学习再学习
Algorithm
每周至少做一个Leetcode算法题
【题目来源】
左程云、《程序员代码面试指南:IT名企算法与数据结构题目最优解(第2版)》如何仅用递归函数和栈操作逆序一个栈
【题目】
一个栈依次压入1、2、3、4、5,那么从栈顶到栈底分别为5、4、3、2、1。将这个栈转置后,从栈顶到栈底为 1、2、3、4、5,也就是实现栈中元素的逆序,但是只能用递归函数来实现,不能用其他数据结构。
【解答】
构造递归方法getAndRemoveLastElement(Stack<Integer> stack)
,方法返回stack的栈底元素并将其移出stack。
真正的逆序方法reverse(Stack<Integer> stack)
递归调用getAndRemoveLastElement()
参考代码如下:
public class A12_InvertStack {
public A12_InvertStack() {}
// 辅助方法
public static int getAndRemoveLastElement(Stack<Integer> stack) {
int result;
result = stack.pop();
if (stack.isEmpty()) {
return result;
}else {
int last = getAndRemoveLastElement(stack);
stack.push(result);
return last;
}
}//End getAndRemoveLastElement()
// 逆序Stack的方法
public static void reverse(Stack<Integer> stack) {
if (stack.isEmpty()) {
return ;
}
int i = getAndRemoveLastElement(stack);
reverse(stack);
stack.push(i);
}
}
【思考讨论】
- 递归调用时,变量result,last,i问什么是多个不同的值而非覆盖?
- 本题递归的出口在哪里?
- 试着在纸上画出递归调用的过程并解释?
Review
阅读并点评至少1篇英文技术文章
原文:RESTful API Designing guidelines — The best practices
译文:
REST风格API设计规范-最佳实践
Mahesh Haldar
Facebook, Google, Github, Netflix 和少数其他科技巨头给开发者和产品一个机会,通过各种API来消费他们的数据,这些巨头对开发者和产品来说已经变成一个平台。
尽管你没有给开发者和产品写API,拥有美观和技巧娴熟的API对你的应用来说总是及其有益的。
在网上一直持续着关于设计API的最佳方式的争论,这是最微妙的事情之一,同时这点没有任何官方的规范。
API是一个接口,许多开发者通过它和数据交互。一个好的API设计总是使用方便、帮助开发者更顺畅的开发。API对开发者来说是图形用户界面,如果他用起来令人困惑或者说明不够详细,那么开发者将会开始寻找它的替代品或者停止使用它。开发者的体验是衡量API质量的最重要的尺度。
API好比在舞台上表演的艺术家,它的用户就是观众。
1)术语
下面这些是REST风格API中最重要的术语
- Resource资源是一个对象或者某些东西的代表,它包含一些相关的数据,可以有一些操作资源的方法。例如,动物,学校,员工是资源,删除,添加,更新是在这些资源上展现的操作。
- Collections集合是一堆资源,例如,是单数和复数的关系。
- URL(Uniform Resource Locator)统一资源定位器是一个路径,通过它可以定位一个资源,一些行为可以这个资源执行。
2)API 端点
让我们来写几个API来加深理解,针对包含Employees的Companies。/getAllEmployees
是一个响应返回employees列表的API,其他几个关于一个Company的API类似下面这些
/addNewEmployee
/updateEmployee
/deleteEmployee
/deleteAllEmployees
/promoteEmployee
/promoteAllEmployees
有一大堆像这些一样的,针对不同的操作的API端点。所有这些API端点包含了许多不同的行为,因此当API的数量增加时,这些端点维护起来压力重重。
到底怎么了?
URL应该只包含Resource(名词)而不含行为或者动词。路径/addNewEmployee
包含了动作addNew
和资源名字Employee
。
那么什么是正确的方式呢?
/companies
端点是一个正例,它不含行为。但问题是我们如何告诉服务器要在companies资源上执行什么行为呢,是add,delete还是update呢?
这是HTTP方法(GET, POST, DELETE, PUT)也称之为动词扮演的角色。
资源在API端点中应该总是复数形式,如果我们想选择资源的一个实例,我们可以在URL中加上id。
- method
GET
path/companies
应该获取所有companies的列表 - method
GET
path/companies/34
应该获取company 34的详情 - method
DELETE
path/companies/34
应该删除company 34。
在一些其他使用场景下,如果在一个资源下有许多资源,例如Employees of a Company,下面是几个API端点的样本:
GET /companies/3/employees
表示从company 3中获取所有employees的列表GET /companies/3/employees/45
表示获取employee 45的详情,它属于company 3DELETE /companies/3/employees/45
表示删除employee 45,它属于company 3POST /companies
表示创建一个新的company并且返回新创建的company的详情
现在API是不是更准确和一致性更好呢?得意
总结:路径应该包含资源的复数形式,HTTP方法应指定是GET, POST, DELETE, PUT具体哪种行为。
3)HTTP方法(动词)
HTTP已经定义了一些方法,它们显示将要在资源上执行的行为的类型
URL是一个句子,其中资源是名词,HTTP方法是动词
重要的HTTP方法如下:
1.GET方法请求从源获取数据同时不产生任何负面影响
例如/companies/3/employees
返回来自company 3的所有employees的列表
2.POST方法请求服务器在数据库中创建一个源,通常发生在web表单提交时。
例如/companies/3/employees
在company 3中穿件了一个新的Employee。POST是非幂等的,意味着多个请求会有不同的影响。
3.PUT方法请求服务器更新资源或者在不存在时创建资源
例如/companies/3/employees/john
将请求服务器来更新或者如果它不存在,创建john资源在company 3的employees集合中。
PUT是幂等的,意味着多个请求产生相同的影响。
4.DELETE方法请求资源或者他的实例应该从数据库中移除。
例如/companies/3/employees/john
将请求服务器从company 3的employees集合中删除john资源。
这里有一些其他的方法,我们将在另外一篇博客中讨论
4)HTTP响应状态码
当客户端通过API向服务端提交请求后,客户端应该知道反馈情况,请求是失败了,通过了还是错误。HTTP状态码是一系列的标准值,在不同的场合不同的解释。服务端应该总是返回正确的状态码。
以下是重要的HTTP状态码的目录
【注】:状态码的含义可以在用到时具体去查
2XX(成功系列)
这些状态码代表请求的行为已经收到并且服务端成功的处理了。
-
200 OK 标准的HTTP代表成功的响应,针对GET、PUT或POST。
-
201 Created当新的实例被创建时应该返回这个状态码。例如使用POST方法,创建了一个新的实例,应该返回201。
-
204 No Content表示请求成功处理了,但是没有返回任何内容。
DELETE是一个很好的例子
3XX(重定向系列)
- 304 Not Modified表示客户端有了已经存在缓存里的响应,因此不需要再次传输相同的数据。
4XX(客户端错误系列)
代表客户端提了一个错误的请求
- 400 Bad Request表示请求未处理,因为服务器不能理解客户端要什么?
- 401 Unauthorized 没有权限访问
- 403 Forbidden
- 404 Not Found 表示请求的资源现在不能用了
- 410 Gone
5XX(服务器错误系列)
- 500 Internal Server Error 表示请求有效,但是服务器完全迷惑不解,服务器
- 503 Service Unavailable
5)域名命名规范
你可以遵循任意的命名规范,但确保在整个应用是保持一致的。如果你的请求体或者响应类型是JSON,那么请遵循驼峰命名来保持一致性。
6)搜索、排序、过滤和分页
所有这些行为仅仅查询一个数据集。没有新的API来处理这些行为。我们需要给GET方法API增加查询参数。让我们通过几个例子来理解如何实现这些行为。
-
排序客户端希望获得已经排过序的公司列表,
GET /companies
端点应该在查询中接收多个排序参数,例如GET /companies?sort=rank_asc
将会通过公司的排名升序排列。 -
过滤为了过滤数据集,我们可以用查询参数做各种选项,例如
GET /companies?category=banking&location=india
表示将用银行类并且属地是印度的条件来筛选公司列表数据 -
搜索当在公司列表中搜索公司名时,API的端点应该是
GET /companies?search=Digital Mckinsey
-
页码当数据集太大时,我们把数据集分成更小的块,这个处理在提升性能和易于处理响应方面起到了很大帮助。例如
GET /companies?page=23
表示获取第23页的公司列表。如果在GET方法上添加许多查询参数导致URI太长,服务器返回414 URI太长的HTTP状态,在这种情况下,参数也可以POST方法的请求体中来传递。
7)添加版本
当世界使用你的API时,因为有一些大的变化,需要升级API,这也导致突破了现存的产品或者服务使用你的API时。
http://api.yourservice.com/v1/companies/34/employees
时一个好的例子,在路径里有API的版本号。如果有任何主要的、突破性的更新,我们可以命名新的API集合叫v2
或者v1.x.x
。
这些指导建议由我的开发经验总结而来。我很乐意知道你关于上面提到的那些点的看法。请留言让我知道。
Tip
学习至少一个技术技巧
面试官:聊一下static吧!
- static 修饰的方法/变量,直接用“类名.方法/变量”格式调用,如:
Math.PI
,Math.random()
; - 静态方法不能使用非静态变量(实例变量),因为没有指明实例变量属于谁。同理,也不能调用非静态方法。
- 静态变量是one per class的,该类的所有实例共享同一份。
- 静态变量的初始化:随着类的加载而初始化,在静态方法运行之前进行
- static final variable 是常量
- static代码块可以用于常量的初始化,执行早于static变量初始化早于静态方法执行
Share
分享一篇有观点和思考的技术文章
推荐一本Java的经典书籍《Head First Java 2nd Edition》,本书的作者Kathy sierra深入浅出的将OO做了透彻的讲解,本书代码基于Java 5编写。符合以下任意一点,强烈建议阅读本书:
- 有模棱两可的问题,久久没解决
- OO基础不牢固
- 学了的Java知识记不住
链接:https://pan.baidu.com/s/1WgAWQo73bhc9Yx4ZMOCu5w
提取码:pehu