MO_or

MO_or 查看完整档案

成都编辑成都航空职业技术学院  |  软件技术 编辑成都易云智远科技有限公司  |  软件开发 编辑填写个人主网站
编辑

小菜鸟的成长地。

个人动态

MO_or 收藏了文章 · 9月30日

2020 Java开发者数据分析:中国已成为 Java 第一大国

最近知名开发工具供应商Jetbrains在Java 25周年之际,对开发群体做了一次有意思的数据分析。

全文内容可见:https://blog.jetbrains.com/id...

通过这次的分析,得出了非常多意思的结论,接下来我们一起来快速看看,都有哪些有意思的现象出现!

有多少Java开发者?

  1. 专业Java开发人数约 520万
  2. 算上主要使用其他语言但也使用Java的开发人员约680万

Java开发者都在哪里?

  1. 亚洲最多,大约有250万

file

  1. 中国最多,韩国第二,分别占据了51%、50%

file

编程语言的使用占比

根据2020年开发者生态系统调查,超过三分之一的专业开发者使用 Java 作为主要语言,Java 仍然是继 JavaScript 之后专业开发者使用的第二主要语言。

  1. 专家分析看到 JavaScript 和 Java 处于领先地位并不令人惊讶,因为它们是一对,使用 Java 的开发人员经常用 JavaScript 编写前端和任何快速的脚本。
  2. 由于机器学习的普及,Python 可能排在第三位。
  3. 我们希望 web 成为开发者生态系统的重要组成部分,因此 JavaScript、 HTML、 CSS 和 PHP 将永远站得住脚。
  4. SQL 也将一直存在,因为没有什么不需要数据库的容量。
  5. C + + 也是一种坚实的语言,因为它被用于许多嵌入式应用程序,所以它不会很快从图表中消失。
  6. 尽管 c # 似乎正在失去优势,我猜如果 Java 是高的,那么 c # 将是低的,因为它们在功能上非常相似。

file

都用Java开发些啥?

  1. Web 服务是使用 Java 最流行的领域,占52% 。
  2. 看到 Java 在商业智能/数据科学/机器学习领域如此普遍令人惊讶,因为你可能认为这是 Python 的领域。

file

使用Java的几个主要行业

  1. Java 程序员主要工作在 IT 服务(42%)和金融和金融技术(44%) ,但这并不是说 Java 不用于其他行业。
  2. 专家分析金融和金融科技行业主要是金融交易所、零售银行系统、创建计算引擎、开发自主定制工具和服务,以提高公司在市场上的竞争力。金融和金融科技基本上都建立在Java,所以这里没有什么可惊讶的。
  3. IT 服务也是如此,因为许多非 IT 公司的工资系统和库存管理服务都是基于 Java 构建的。其他行业也很有意思。
  4. 由于 Android,移动开发可能很高,所以 Java 被用在这个能力上。大数据和数据分析是非常有趣的,因为这个行业是由 Python 引领的,但是在后端可能会有一些 Java 和 JVM 语言的用途。
  5. 当然是软件开发工具。目前使用 Java 构建 JetBrains。

file

Java版本的选择

  1. Java 8仍然是最流行的版本
  2. Oracle引入了每两年发布一次的版本,所以并不是所有的版本都能在很长一段时间内得到支持,所以 java 9、 java 10、 java 12和 java 13只能在6个月内得到支持,这可能就是为什么它们的用户都非常少的原因。
  3. java 13之所以如此之高,是因为当这个调查结果公布时,它是最新版本,所以你可以预期这个数字在几个月内会下降
  4. java 11发布于2018年,是最新的长期支持版本。许多企业仍然没有采取行动,因为他们担心过去的 java9(及其架构的变化)将打破一切,而且 java11引入了新的许可和新的订阅,所以它带来了额外的担心,如果你用错了版本,以错误的方式,甲骨文将罚款你。同时,不更新到Java 11的最后一个重要原因是它没有很多令人兴奋的新特性

file

最流行的应用服务器

  1. 毫无疑问,第一是Apache Tomcat
  2. Jetty 排在第二位,但它似乎出人意料地低。可能是一些使用 Spring Boot 和其他微服务框架的开发人员可能都没意识到他们在使用什么(Spring Boot内嵌模式让开发者无感知)

file

五大Web开发框架

  1. SPring Boot第一、Spring MVC第二
  2. 这一调查证实了Spring在Web开发领域的霸主地位

file

五大Java开发工具

IntelliJ IDEA 的份额从2018年的55% 增加到2020年的72%,而其他的都在逐年减少

file

本文首发:2020 Java开发者数据分析:中国已成为 Java 第一大国,转载请注明该文链接

欢迎关注我的公众号:程序猿DD,获得独家整理的免费学习资源助力你的Java学习之路!另每周赠书不停哦~

查看原文

MO_or 赞了文章 · 9月30日

2020 Java开发者数据分析:中国已成为 Java 第一大国

最近知名开发工具供应商Jetbrains在Java 25周年之际,对开发群体做了一次有意思的数据分析。

全文内容可见:https://blog.jetbrains.com/id...

通过这次的分析,得出了非常多意思的结论,接下来我们一起来快速看看,都有哪些有意思的现象出现!

有多少Java开发者?

  1. 专业Java开发人数约 520万
  2. 算上主要使用其他语言但也使用Java的开发人员约680万

Java开发者都在哪里?

  1. 亚洲最多,大约有250万

file

  1. 中国最多,韩国第二,分别占据了51%、50%

file

编程语言的使用占比

根据2020年开发者生态系统调查,超过三分之一的专业开发者使用 Java 作为主要语言,Java 仍然是继 JavaScript 之后专业开发者使用的第二主要语言。

  1. 专家分析看到 JavaScript 和 Java 处于领先地位并不令人惊讶,因为它们是一对,使用 Java 的开发人员经常用 JavaScript 编写前端和任何快速的脚本。
  2. 由于机器学习的普及,Python 可能排在第三位。
  3. 我们希望 web 成为开发者生态系统的重要组成部分,因此 JavaScript、 HTML、 CSS 和 PHP 将永远站得住脚。
  4. SQL 也将一直存在,因为没有什么不需要数据库的容量。
  5. C + + 也是一种坚实的语言,因为它被用于许多嵌入式应用程序,所以它不会很快从图表中消失。
  6. 尽管 c # 似乎正在失去优势,我猜如果 Java 是高的,那么 c # 将是低的,因为它们在功能上非常相似。

file

都用Java开发些啥?

  1. Web 服务是使用 Java 最流行的领域,占52% 。
  2. 看到 Java 在商业智能/数据科学/机器学习领域如此普遍令人惊讶,因为你可能认为这是 Python 的领域。

file

使用Java的几个主要行业

  1. Java 程序员主要工作在 IT 服务(42%)和金融和金融技术(44%) ,但这并不是说 Java 不用于其他行业。
  2. 专家分析金融和金融科技行业主要是金融交易所、零售银行系统、创建计算引擎、开发自主定制工具和服务,以提高公司在市场上的竞争力。金融和金融科技基本上都建立在Java,所以这里没有什么可惊讶的。
  3. IT 服务也是如此,因为许多非 IT 公司的工资系统和库存管理服务都是基于 Java 构建的。其他行业也很有意思。
  4. 由于 Android,移动开发可能很高,所以 Java 被用在这个能力上。大数据和数据分析是非常有趣的,因为这个行业是由 Python 引领的,但是在后端可能会有一些 Java 和 JVM 语言的用途。
  5. 当然是软件开发工具。目前使用 Java 构建 JetBrains。

file

Java版本的选择

  1. Java 8仍然是最流行的版本
  2. Oracle引入了每两年发布一次的版本,所以并不是所有的版本都能在很长一段时间内得到支持,所以 java 9、 java 10、 java 12和 java 13只能在6个月内得到支持,这可能就是为什么它们的用户都非常少的原因。
  3. java 13之所以如此之高,是因为当这个调查结果公布时,它是最新版本,所以你可以预期这个数字在几个月内会下降
  4. java 11发布于2018年,是最新的长期支持版本。许多企业仍然没有采取行动,因为他们担心过去的 java9(及其架构的变化)将打破一切,而且 java11引入了新的许可和新的订阅,所以它带来了额外的担心,如果你用错了版本,以错误的方式,甲骨文将罚款你。同时,不更新到Java 11的最后一个重要原因是它没有很多令人兴奋的新特性

file

最流行的应用服务器

  1. 毫无疑问,第一是Apache Tomcat
  2. Jetty 排在第二位,但它似乎出人意料地低。可能是一些使用 Spring Boot 和其他微服务框架的开发人员可能都没意识到他们在使用什么(Spring Boot内嵌模式让开发者无感知)

file

五大Web开发框架

  1. SPring Boot第一、Spring MVC第二
  2. 这一调查证实了Spring在Web开发领域的霸主地位

file

五大Java开发工具

IntelliJ IDEA 的份额从2018年的55% 增加到2020年的72%,而其他的都在逐年减少

file

本文首发:2020 Java开发者数据分析:中国已成为 Java 第一大国,转载请注明该文链接

欢迎关注我的公众号:程序猿DD,获得独家整理的免费学习资源助力你的Java学习之路!另每周赠书不停哦~

查看原文

赞 6 收藏 4 评论 0

MO_or 发布了文章 · 8月11日

个人感悟 | MO_or的No.002:为什么断更两个月?

image
笔者在五月的时候裸辞了。顶着各方的压力,最终还是任性了一把。

并不想任何读者借鉴我的案例,我只希望读者通过我的案例,多了解到一种生活体验。

很感谢每一段经历。


回到正题,为什么断更了呢?

断更主要是因为两点,第一是笔者陷入了较长的一个自醒阶段,第二是自醒阶段过后,笔者便开始找工作了。

在自醒阶段笔者花了很多时间来正视自己的过往,思考自己的未来,规划自己的当下。


过往的一些事

有的初中同学已经结婚生子了,于是去赴了宴,这么大了第一次在初中同学面前唱了KTV,以前一直很排斥,也很胆怯。
去看望了一个正在考研的初中同学,曾经我“讨厌”她,现在想来其实是初中时的矫情,懵懵懂懂的喜欢用刻意冷漠来掩盖。
在家呆了两个周,是的就是呆呆的在家里,父母没给我什么压力,也看出了我的迷茫,但自己的路还是想自己选,父母带我和他们的同事一起吃了吃饭,我也第一次认真地去了解了父辈这代人的过往。


未来的一些事

笔者在年初时做了一个较详细的年度计划,下面是年度计划的部分
但这更多针对的是目前所需要解决的问题
image
而我想做什么?我想成为什么样的人?我想要怎样的生活?这才是一直困扰着笔者的问题
笔者在此期间去做了些尝试:

  • 健身,自己做减肥餐,一个多月瘦了20多斤,多了一些朋友
  • 学习理财,看了些理财入门的书,对金钱产生了新的看法
  • 自考本科,真正自学后才发现,自学对综合能力的提升是非常巨大的
  • 面试,面试是很好的一个和不同领域的人沟通的好机会,认识到了自己的一些问题,也得到了一些人的认可。可以和不同年龄段的人聊天,让我看世界的角度更加宽广了

虽然上面的三个问题还是没有得到一个明确的答案,但这些探索让我感觉到越来越接近了


现在的一些事

健身已停止一个多月了,所幸体重没有反弹
现在笔者注意力回归到了工作与学习中,安静的夯实自己的基础,继续探索
先努力成为一名合格的软件工程师


分享:

书:
《英语(二)自学教程》
《你的灯亮着吗?》
《小狗钱钱》
《小狗钱钱2》
《富爸爸穷爸爸》

乐:
《膨胀(翻自 陆通)》—— 于梓贝
《F**k you(翻自 Lily Allen)》—— 于梓贝
《熬夜上瘾(翻自 刘亦心(可乐就是力量))》—— 于梓贝
《崖の上のポニョ》—— 久石譲
《Landing Guy》—— 刘昊霖/kidult
《迷藏》—— 刘昊霖
《谈恋爱》—— 张尕怂
《鱼儿》—— 鲁向卉
《张三的歌(Live)》—— 胡夏
《张三的歌(Live)》—— 齐秦
《张三的歌》—— 蔡琴
《路过人间(Walking by the world)》 —— 郁可唯
《Baby Song》—— 陈奕迅
《歩いても 歩いても(步履不停)》—— ゴンチチ

————————以上歌曲网易云音乐均有————————

乐队:好妹妹

影:
《本杰明·巴顿奇事》
《宫崎骏:十年一梦》
《我是XX生》
《妙先生》
《与全世界做生意》


最后:
C'est la vie.
你好,我是MO_or,请多指教。

查看原文

赞 0 收藏 0 评论 0

MO_or 发布了文章 · 8月10日

MO_or使用Spring Boot整合Swagger2

一、Swagger?

1.1 什么是Swagger?

  • 官方说法:Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步

1.2 什么是SpringFox?

  • 官方定义为: Automated JSON API documentation for API's built with Spring,是一个开源的API Doc的框架, 它的前身是swagger-springmvc,可以将我们的Controller中的方法以文档的形式展现
  • 下文中需要导入的几个maven依赖就是通过SpringFox整合Swagger,以此来支持在Spring框架下进行使用

1.3 Swagger2的作用

这里指的Swagger2为,springfox-swagger2。通过这个依赖就可在spring中使用swagger的注解
  1. 可以生成文档形式的api,提供给不同团队
  2. 方便自测,方便领导查阅
  3. 无需过多冗余的word文档或网页文档

二、导入的maven依赖

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.7.0</version>
</dependency>

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.7.0</version>
</dependency>

三、自定义配置类

@Configuration
public class Swagger2Config {

    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.im.controller"))//需要生成文档所在的包
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("springboot使用swagger2构建api文档")//文档标题
                .description("简单优雅的restful风格,http://blog.csdn.net/saytime")//描述
                .termsOfServiceUrl("http://blog.csdn.net/saytime")
                .version("1.0")
                .build();
    }
}

四、测试

4.1 User实体类

@ApiModel(value = "用户实体")
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class User {

    @JsonIgnore
    @ApiModelProperty(name = "用户车辆",dataType = "Car" ,notes = "用户车辆")
    private Car car;

    public User(Integer userId, String userName, String password, String email, String birthDate) {
        this.userId = userId;
        this.userName = userName;
        this.password = password;
        this.email = email;
        this.birthDate = birthDate;
    }

    @ApiModelProperty(name = "用户id", dataType = "Integer", notes = "用户id")
    private Integer userId;

    @ApiModelProperty(name = "用户名", dataType = "String", notes = "用户名")
    private String userName;

    @ApiModelProperty(name = "密码", dataType = "String", notes = "密码")
    private String password;

    @ApiModelProperty(name = "邮箱", dataType = "String", notes = "邮箱")
    private String email;

    @ApiModelProperty(name = "生日", dataType = "String", notes = "生日")
    private String birthDate;

}
PS:实体类中已经用了@AllArgsConstructor,但还是写了一个带参构造器,是因为笔者自测时用了static{}静态代码块来初始化对象,static{}的优先级是高于注解的,所以若没有自己写带参构造器是无法通过编译的

4.2 UserController

@RestController
@RequestMapping("/user")
@Api(value = "用户服务", description = "用户的基本操作")
public class UserController {

    @ApiOperation(value = "用户列表服务", notes = "查詢所有用戶的列表信息")
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public List<User> list() {
        List<User> userList = new ArrayList<>();
        for (String key : DataNode.users.keySet()) {
            userList.add(DataNode.users.get(key));
        }
        return userList;
    }

    @ApiOperation(value ="根据用户ID查询用户信息",notes="根据url的id来获取用户详细信息")
    @ApiImplicitParam(name="userId",value = "用户ID",required = true,dataType ="Integer",paramType = "path")
    @RequestMapping(value = "/findOneById/{userId}",method = RequestMethod.GET)
    public User findOneById(@PathVariable("userId") Integer userId) {
        for(String key: DataNode.users.keySet()) {
            User user = DataNode.users.get(key);
            if(user.getUserId().equals(userId)) {
                return user;
            }
        }

        return null;
    }

    @ApiOperation(value = "根据用户名获取用户信息")
    @RequestMapping(value = "/findOneUserName/{userName}",method = RequestMethod.GET)
    @ApiImplicitParam(name = "userName",value = "用户名",required = true,dataType = "String",paramType = "path")
    public User findOneByName( @PathVariable("userName") String userName) {
        for(String key: DataNode.users.keySet()) {
            User user = DataNode.users.get(key);
            if(userName.equals(user.getUserName())) {
                return user;
            }
        }

        return null;
    }

    @ApiOperation(value = "根据用户名获取用户信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "int", paramType = "query"),
            @ApiImplicitParam(name = "userName", value = "用户名称", required = true, dataType = "String", paramType = "query")
    })
    @RequestMapping(value = "/findOneByIdAndName",method = RequestMethod.GET)
    public User findOneByIdAndName(@RequestParam String userName, @RequestParam Integer id) {
        for(String key: DataNode.users.keySet()) {
            User user = DataNode.users.get(key);
            if(user.getUserName().equals(userName) && id.equals(user.getUserId())) {
                return user;
            }
        }

        return null;
    }

    @ApiOperation(value = "根据查询条件获取用户信息")
    @RequestMapping(value = "/findOneByCondition",method = RequestMethod.GET)
    public User findOneByCondition(UserCondition userCondition) {
        for(String key: DataNode.users.keySet()) {
            User user = DataNode.users.get(key);
            if(user.getUserName().equals(userCondition.getUserName()) &&
                    user.getUserId().equals(userCondition.getUserId())) {
                Car car = new Car();
                car.setName("奥迪");
                user.setCar(car);
                return user;
            }
        }
        return null;
    }
}

4.3 测试样列

image

image

五、参考

六、最后

若有不足,敬请指正
虚心若愚,求知若渴
查看原文

赞 1 收藏 1 评论 0

MO_or 发布了文章 · 7月24日

MO_or关于Lambda表达式的学习

lambda.jpeg

一、引言

本文将探讨 JDK 1.8 中引入的新特性 Lambda (λ) 表达式
主要解决如下几个问题:

  1. 什么是函数式接口?
  2. 函数式接口的作用是什么?
  3. 什么是 Lambda 表达式?
  4. Lambda 表达式的作用是什么?
  5. Lambda 表达式的演化过程
  6. Lambda 表达式的简化过程

二、什么是函数式接口

接口的方法默认是public abstract,都是抽象方法,而函数式接口则有且仅有一个抽象方法,但可以有多个非抽象方法,通常用注解进行标识

@FunctionalInterface

这里列举一些JDK 1.8以前常用的函数式接口:

  • java.lang.Runnable
  • java.util.concurrent.Callable
  • java.util.Comparator
  • java.io.FileFilter
  • java.awt.event.ActionListener

在JDK 1.8中新增了如下函数式接口:

  • Consumer(类似于消费者需要传入参数无返回值)
  • Supplier(类似于生产者不需要传入参数,但有返回值)
  • Function(有输入也有返回)
  • Predicate(判断函数,有输入也有返回,返回true or false

三、函数式接口的作用是什么?

因为Java是面向对象的,方法间参数传递需要为对象,而不能是方法,若想向方法传递方法,则需要一个只有一个抽象方法的接口实现类的对象,将这个对象传到方法中就实现了向方法传递方法。
总结:函数式接口便是为了解决向方法传递方法的需求,将需要传递的方法转为一个函数式接口对象(有且仅有一个抽象方法的接口实现类),以此来解决向方法传递方法的需求。

3.1 进一步再思考一个问题 “为什么要向方法传递方法?”

笔者是这样认为的,大部分问题实际是围绕时间和空间的问题,就像不同的数据结构是在做时间和空间上的取舍,是为了节约更多空间,而牺牲一点时间,或者是为了节约更多时间,而占用更多空间。
用相同的思考模式去看编程语言的升级其实也是这样的,是为了降低编程难度,使代码更易懂更易用,这样就可以节约更多的时间去做别的,而不是花费过多时间去编码。
而上面的问题其实也是为了让代码更易懂更易用,至于怎么体现出更易懂更易用的,读者可以独自思考思考。

四、什么是 Lambda 表达式?

Lambda表达式可以将函数作为一个方法的参数

五、Lambda 表达式的作用是什么?

  1. 避免匿名内部类定义过多
  2. 让代码更简洁,更易读
  3. 去掉过多冗余、修饰性的代码,只保留核心逻辑

这就就好比语法糖,能让代码更好写也更好读。但笔者也知道,任何新的东西引入必然带来新的混乱,学习新的知识需要过程,适应也需要过程,但其最终的回报笔者认为是值得的。

六、Lambda 表达式的演化、简化过程

// 方式一、函数式接口
@FunctionalInterface
interface ILike {

    // 接口中的访问修饰符、abstract修饰符是可以省略的
    // 因为接口中默认就是抽象方法,又因为接口是需要实现类来实现其中方法的
    // 所以访问修饰符默认是public
    void lambda();

}

// 方式一、实现函数式接口中的抽象方法
class Like implements ILike {

    @Override
    public void lambda() {
        System.out.println("Lambda 1");
    }
}

public class TestLambda {

    // 方式二:静态内部类
    static class Like1 implements ILike {

        @Override
        public void lambda() {
            System.out.println("Lambda 2");
        }
    }

    public static void main(String[] args) {

        // 方式一:函数式接口
        ILike like = new Like();
        like.lambda();

        // 方式二:静态内部类
        like = new Like1();
        like.lambda();

        // 方式三:局部内部类
        class Like2 implements ILike {

            @Override
            public void lambda() {
                System.out.println("Lamdba 3");
            }
        }
        like = new Like2();
        like.lambda();

        // 方式四:匿名内部类,没有类的名称,必须借助接口或父类
        like = new ILike() {
            @Override
            public void lambda() {
                System.out.println("Lamdba 4");
            }
        };
        like.lambda();

        // 方式五:Lamdba表达式,只保留具体的方法
        // 前提是必须为函数式接口
        like = () -> {
            System.out.println("Lambda 5");
        };
        like.lambda();

    }

}

七、参考

八、最后

若有不足,敬请指正
虚心若愚,求知若渴

查看原文

赞 0 收藏 0 评论 0

MO_or 关注了用户 · 6月1日

敖丙 @aobing

关注 3804

MO_or 发布了文章 · 5月28日

MO_or查漏补缺之Java基础篇

java_se.png

1. == 和 equals() 的区别是什么?

== 的作用:
  • 基本数据类型:判断值是否相等
  • 引用数据类型:判断引用地址是否相等,String类型要单独讨论
equals() 的作用:
  • 在Object中和 == 一样是判断引用地址是否相等

equals object.png

  • 在String中是判断其字符串值是否相等

equals string.png

内存模型

创建三个String对象,如下图所示
String内存模型.png

  1. str1通过new会在堆创建一个字符串对象
  2. str2直接创建也会在堆创建一个字符串对象
  3. str3直接创建,但并不会在堆创建一个字符串对象,而是直接指向str2在堆的字符串对象。因为没有通过new创建的String对象,会先在字符串池中去找是否已有值相等的String对象,若有则将栈指针指向堆中已有的String对象,若没有才会在堆中创建新的String对象

2. 两个对象的hashCode()相同,则equals()一定为true,对吗?为什么?

hashCode():是根据内存地址按hash算法得出的一个正数

若equals()为true,hashCode()也为true
若hashCode()为true,equals()不一定为true,因为可能存在hash冲突(概率较低)

那么hashCode在实际应用中有什么作用呢?

以HashSet为例确保添加的元素是不重复的:

  • 重写hashCode()与equals()方法
  • 先判断hash值是否相等,若不等,则元素不重复
  • 若hash值相等,再判断equlas()值是否相等,如值不等则元素不重复
那么为什么要使用hashCode呢?

如果在存储的时候逐个equals()比较,效率较低,哈希算法提高了去重复的效率,降低了使用equals()方法的次数

3. String类的常用方法?

判断功能
boolean equals(Object obj)
boolean equalsIgnoreCase(String str)
boolean isEmpty()
boolean contains(String str)
boolean startsWith(String str)
boolean endsWith(String str)
获取功能
int length()
char charAt(int index)
int indexOf(int ch)
int indexOf(String str)
int indexOf(int ch,int fromIndex)
int indexOf(String str,int fromIndex)
String substring(int start)
String substring(int start,int end)
转换功能
byte[] getBytes()
char[] toCharArray()
static String valueOf(char[] chs)
static String valueOf(int i)
String toLowerCase()
String toUpperCase()
String concat(String str)
其它功能
  • 替换功能
String replace(char old,char new)
String replace(String old,String new)
  • 去除字符串两空格
String trim()
  • 按字典顺序比较两个字符串
int compareTo(String str)
int compareToIgnoreCase(String str) 

4. final的作用?

修饰类

表示该类不能被继承,请谨慎使用,若非该类已十分明确不会被继承或出于安全方面考虑,并不建议设计为final类

修饰方法

表示该方法不能被子类重写(覆盖),但能够被重载,即在子类中可以创建多个与final方法方法名相同,但参数不同的方法
注意若父类中final方法的访问修饰符为private,那么子类是不会直接继承父类的final方法的,那么这时在子类中创建相同的方法名与参数是不会有final冲突的

修饰变量

final修饰变量是较为常见的,也是这里需要重点学习的部分
final修饰变量表示该变量仅能被赋值一次,赋值后值不再改变

  • 当为基本数据类型时,表示其初始化后就不能再被更改
  • 当为引用数据类型时,表示其初始化后就不能再指向其它对象,但被指向的对象是可以更改的,其本质是一样的即保证栈中的地址是无法更改的
  • 当为成员变量时,必须要显示初始化,即声明变量时就初始化,或声明变量时未初始化,但在该成员变量的类中所有构造方法(无参、有参)中赋初值
  • 当为参数时,表示该参数只读,只能读取使用,但不能被更改

5. IO流分几种?

按数据类型分:
  • 字节流:InputStream、OutputStream,任何数据类型都能支持
  • 字符流:Reader、Writer,非纯文本格式数据可能会导致文件格式破坏
按数据流向分:
  • 输入流:读取文件数据
  • 输出流:将数据写入文件中
按功能分:
  • 字节流:FileInputStream、FileOutputStream,直接和源数据进行输入输出
  • 处理流:在字节流的基础上进行了功能的扩展或加强,又分为以下两种

    • 转换流:InputStreamReader、OutputStreamWriter,字节流转字符流,字符流转字节流
    • 缓冲流:BufferedInputStream,BufferedOutputStream   BufferedReader,BufferedReader,可对节点流经行包装,使读写更快

扩展:关于缓冲流,这里涉及到了设计模式中的装饰者模式,其作用即基于已有功能基础上,提供增强的功能

其实现思路如下:

  1. 子类继承父类
  2. 子类中声明一个父类类型的成员变量
  3. 通过子类中的带参构造方法接收外部传递的父类类型参数,并赋值给子类的父类成员类型成员变量
  4. 在实现功能时,调用外部传递的父类类型参数实现原有功能,自己实现增强功能

6. BIO、NIO、AIO有什么区别?

先结合生活场景简单介绍下同步、异步、阻塞、非阻塞,以银行取款为例:

  • 同步:自己到银行取款
  • 异步:委托别人(将各种需要的资料给别人)帮自己到银行取款,期间自己可以做别的,然后等别人取好给自己
  • 阻塞:在ATM排队取款,只能站着等
  • 非阻塞:在银行取个号,坐椅子上玩自己的,等广播叫号到自己了就去,没到号不能插队,也可以不断问大堂经理到自己没,如果说没到就不能去
BIO(Blocking I/O)

同步且阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善

BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解

NIO(Non-Blocking I/O)

同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理

NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持

AIO(Asynchronous I/O)

异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理

AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持

扩展:Netty为什么使用NIO而不是AIO?

Netty不看重Windows上的使用,在Linux系统上,AIO的底层实现仍使用EPOLL,没有很好实现AIO,因此在性能上没有明显的优势,而且被JDK封装了一层不容易深度优化

参考:为什么Netty使用NIO而不是AIO?

7. Files的常用方法?

Files.read()    读取文件
Files.write()   写入文件
Files.exists()  检测文件路径是否存在
Files.createFile()  创建文件
Files.createDirectory() 创建文件夹
Files.delete()  删除文件或者目录
Files.copy()    复制文件
Files.move()    移动文件
Files.size()    查看文件个数

8. abstract的作用?

抽象类
  1. public abstract class ClassName{}
  2. 抽象类不能被实例化,只有非抽象子类可以被实例化
  3. 抽象类可以有自己的构造方法
  4. 抽象类不同于接口,接口的接口方法是不允许实现的,但抽象类中普通方法可以被实现
  5. 抽象类不能用final关键字来形容,因为final修饰类表示该类不能被继承,但抽象类需要子类来实现抽象方法
  6. 抽象类中可以没有抽象方法,但只要有一个抽象方法,就一定是抽象类
  7. 继承了抽象类的子类必须全部重写抽象类的方法,只有子类也为抽象类时才可以不用全部重写
  8. 一个类只能单继承抽象类,但可以实现多个接口类
抽象方法
  1. 抽象方法类似与接口中的方法,是不允许在抽象类中实现的,只能由子类来实现
  2. 抽象方法的访问修饰符不能用private,因为private表示只有本类可以调用,而抽象方法需要子类来实现
  3. 抽象方法不能使用static关键字,因为static修饰方法,可以直接通过类名进行调用,但抽象类是不能实例化的
查看原文

赞 0 收藏 0 评论 0

MO_or 发布了文章 · 5月20日

MO_or关于Redis应用篇

redis.jpg

一、引言

本篇文章是Redis的应用篇,若对Redis还不太了解的读者,可以先阅读下笔者的《MO_or关于Redis入门篇

本篇文章将主要探讨以下几点:

  1. Redis的安装(VMware10.0.2 + CentOS 6.5 + Redis 5.0.8 + Xshell)
  2. Redis的五种数据结构(常用的)
  3. string(字符串)
  4. hash(哈希)
  5. list(列表)
  6. set(集合)
  7. zset(有序集合)

二、Redis的安装(可跳过)

这里就不赘述VMware和Linux的安装了,读者可以通过百度或谷歌进行下载并安装

笔者推荐Linux初学者使用Mint和Ubuntu,特别是使用Windows或Mac对可视化界面依赖较高的用户

若目前并不计划学习Linux,Redis也提供了Windows版本Redis-Windows,只需下载解压缩,依次运行redis-server.exe,redis-cli.exe
但笔者并不推荐,因为windows版本都是较老的版本,对于新版本特性的学习是并不具备的,仅能用作入门练习使用(熟悉指令)


下面开始在Linux安装Redis
请确保VMware已安装VMware Tools,否则无法从Windows系统粘贴文件到Linux系统中

1. 下载Redis 5.0.8

download redis.png

2. 将下载的Redis粘贴到Linux系统中

若使用的是CentOS 6.5没有可视化界面的话依次执行如下命令:

yum groupinstall "X Window System" -y
yum groupinstall "Desktop" -y
startx

3. 安装Redis

打开终端,左上角

CentOS终端.png

解压Redis,进入解压文件,编译源码,依次执行如下命令

tar xzf redis-5.0.8.tar.gz
cd redis-5.0.8
make

若遇到异常一:make[2]: cc: Command not found
执行 yum install gcc-c++

若遇到异常二:couldn't execute "tclsh8.5": no such file or directory
执行 yum install -y tcl

若遇到异常三:zmalloc.h:51:31: error: jemalloc/jemalloc.h: No such file or directory
执行 make distclean 再执行 make

4. 运行Redis

打开终端,进入redis文件下的src,依次启动

cd Desktop
cd redis-5.0.8
cd src
./redis-server

5. Xshell连接Redis

查询CentOS ip,执行:ip add
CentOS默认只开放端口22,默认无账号密码
创建Xshell连接,输入ip和端口
启动Redis客户端

cd Desktop
cd redis-5.0.8
cd src
./redis-cli

三、Redis的五种数据结构

这里先列出各种数据结构的大概图形,读者可以先大致了解一下,下面再详细讲解各个数据结构

Redis五种数据结构.png

四、string

4.1 常用操作

SET  key  value                      //存入字符串键值对
MSET  key  value [key value ...]     //批量存储字符串键值对
SETNX  key  value                    //存入一个不存在的字符串键值对
GET  key                             //获取一个字符串键值
MGET  key  [key ...]                 //批量获取字符串键值
DEL  key  [key ...]                  //删除一个键
EXPIRE  key  seconds                 //设置一个键的过期时间(秒)

原子加减

INCR  key                      //将 key 中储存的数字值加 1
DECR  key                      //将 key 中储存的数字值减 1
INCRBY  key  increment         //将 key 所储存的值加上 increment
DECRBY  key  decrement         //将 key 所储存的值减去 decrement

单值缓存

SET  key  value     
GET  key 

对象缓存

方式一:SET  user:1  value(json格式数据)

方式二(推荐):MSET  user:1:name  mo_or   user:1:balance  0
             MGET  user:1:name   user:1:balance
             
方式二操作字段时更加灵活,内存占用也比方式一更小

分布式锁(简单版)

set 命令若重复执行 key值 相同的指令,value值 会被更改
setnx 命令只能添加 key 不存在的 value

SETNX  product:10086  true             //返回 1 代表获取锁成功
SETNX  product:10086  true             //返回 0 代表获取锁失败
/** 执行业务操作 **/
DEL  product:10086                     //执行完业务释放锁
SET product:10086 true  ex  10  nx     //防止程序意外终止导致死锁

4.2 应用场景

计数器

INCR article:readcount:{文章id}         //每点击文章执行一次,阅读量加一
GET article:readcount:{文章id}          //获取文章阅读数

Web集群session共享

spring session + redis实现session共享
(将在之后《进阶篇》中详细讲解)

分布式系统全局序列号

INCRBY  orderId  1000       //redis批量生成序列号提升性能

(将在之后《进阶篇》中详细讲解)

五、hash

结合上面给出的模型图可以看到,hash是key - filed - value 的形式,即 key value 中的 value 又是一个 key value,只不过这个key 叫 filed
(可以想象成 Java 中 map集合 嵌套 map集合)

5.1 常用操作

HSET  key  field  value                        //存储一个哈希表 key 的键值
HSETNX  key  field  value                      //存储一个不存在的哈希表 key 的键值
HMSET  key  field  value [field value ...]     //在一个哈希表 key 中存储多个键值对
HGET  key  field                               //获取哈希表 key 对应的 field 键值
HMGET  key  field  [field ...]                 //批量获取哈希表 key 中多个field键值
HDEL  key  field  [field ...]                  //删除哈希表 key 中的 field 键值
HLEN  key                                      //返回哈希表 key 中 field 的数量
HGETALL  key                                   //返回哈希表 key 中所有的键值
HINCRBY  key  field  increment                 //为哈希表 key 中 field 键的值加上增量 increment

对象缓存

HMSET  user  {userId}:name  mo_or {userId}:balance  0
HMSET  user  1:name  mo_or 1:balance  0  2:name  hero_orz 2:balance  0
HMGET  user  1:name  1:balance  

redis-hash.png

优点

  1. 同类数据归类整合储存,方便数据管理
  2. 相比string操作消耗内存与cpu更小
  3. 相比string储存更节省空间

缺点

  1. 过期功能不能使用在field上,只能用在key上
  2. Redis集群架构下不适合大规模使用

5.2 应用场景

电商购物车

  1. 以用户id为key
  2. 商品id为field
  3. 商品数量为value

购物车操作

hset cart:1001 10088 1             //添加商品
hincrby cart:1001 10088 1          //增加数量
hlen cart:1001                     //商品总数
hdel cart:1001 10088               //删除商品
hgetall cart:1001                  //获取购物车所有商品

购物车.png

六、list

6.1 常用操作

LPUSH  key  value [value ...]           //将一个或多个值 value 插入到 key 列表的表头(最左边)
RPUSH  key  value [value ...]           //将一个或多个值 value 插入到 key 列表的表尾(最右边)
LPOP  key                               //移除并返回 key 列表的头元素
RPOP  key                               //移除并返回 key 列表的尾元素
LRANGE  key  start  stop                //返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定
BLPOP  key  [key ...]  timeout  n(s)    //从 key 列表表头弹出一个元素, 若列表中没有元素,阻塞等待 timeout 秒,如果 timeout=0,一直阻塞等待
BRPOP  key  [key ...]  timeout  n(s)    //从 key 列表表尾弹出一个元素,若列表中没有元素,阻塞等待 timeout 秒,如果 timeout=0,一直阻塞等待

常见数据结构(使用频率较少)

Stack(栈) = LPUSH + LPOP -> FILO(first in last out)
Queue(队列)= LPUSH + RPOP
Blocking MQ(阻塞队列)= LPUSH + BRPOP

redis-list.png

6.2 应用场景

订阅号

下图列表中关注了中国国家地理,四川教育发布

LPUSH  msg:{userId}  10001    //中国国家地理发消息,消息 ID 为 10001
LPUSH  msg:{userId} 10006     //四川教育发布发消息,消息 ID 为 10006
LRANGE  msg:{userId}  0  5    //查看用户最新订阅号消息

订阅号.png

七、set

7.1 常用操作

SADD  key  member  [member ...]             //往集合 key 中存入元素,元素存在则忽略,若 key 不存在则新建
SREM  key  member  [member ...]             //从集合 key 中删除元素
SMEMBERS  key                               //获取集合 key 中所有元素
SCARD  key                                  //获取集合 key 的元素个数
SISMEMBER  key  member                      //判断 member 元素是否存在于集合 key 中
SRANDMEMBER  key  [count]                   //从集合 key 中选出 count 个元素,元素不从 key 中删除
SPOP  key  [count]                          //从集合 key 中选出 count 个元素,元素从 key 中删除

运算操作

SINTER  key  [key ...]                              //交集运算
SINTERSTORE  destination  key  [key ..]             //将交集结果存入新集合destination中
SUNION  key  [key ..]                               //并集运算
SUNIONSTORE  destination  key  [key ...]            //将并集结果存入新集合destination中
SDIFF  key  [key ...]                               //差集运算
SDIFFSTORE  destination  key  [key ...]             //将差集结果存入新集合destination中

集合操作

SINTER set1 set2 set3 -> { c }
SUNION set1 set2 set3 -> { a,b,c,d,e }
SDIFF set1 set2 set3 -> { a }

redis-set.png

7.2 应用场景

抽奖小程序

srandmember指令会按 key 从集合中随机取出 count 个数量的值
spop和srandmember功能类似,但会将取出的值从集合中去除掉

SADD key {userId}                               //点击参与抽奖加入集合
SMEMBERS key                                    //查看参与抽奖所有用户
SRANDMEMBER key [count] / SPOP key [count]      //抽取 count 名中奖者

抽奖.PNG

点赞,收藏,关注(暗示一波(●'◡'●))

SADD  like:{消息ID}  {用户ID}              //点赞
SREM like:{消息ID}  {用户ID}               //取消点赞
SISMEMBER  like:{消息ID}  {用户ID}         //检查用户是否点过赞
SMEMBERS like:{消息ID}                     //获取点赞的用户列表
SCARD like:{消息ID}                        //获取点赞用户数 

八、zset

8.1 常用操作

ZADD key score member [[score member]…]     //往有序集合 key 中加入带分值元素
ZREM key member [member …]                  //从有序集合 key 中删除元素
ZSCORE key member                           //返回有序集合 key 中元素 member 的分值
ZINCRBY key increment member                //为有序集合 key 中元素 member 的分值加上increment 
ZCARD key                                   //返回有序集合 key 中元素个数
ZRANGE key start stop [WITHSCORES]          //正序获取有序集合 key 从 start 下标到 stop 下标的元素
ZREVRANGE key start stop [WITHSCORES]       //倒序获取有序集合 key 从 start 下标到 stop 下标的元素

集合操作

ZUNIONSTORE destkey numkeys key [key ...]       //并集计算
ZINTERSTORE destkey numkeys key [key …]         //交集计算

8.2 应用场景

排行榜

ZINCRBY  hotNews:20200520  1  最全280家5A级景区名单             //点击新闻,点击数加一
ZREVRANGE  hotNews:20200520  0  10  WITHSCORES                 //展示当日排行前十 
ZUNIONSTORE  hotNews:20200514-20200520  7  
hotNews:20200514  hotNews:20200515  ...  hotNews:20200520      //七日搜索榜单计算
ZREVRANGE hotNews:20200514-20200520  0  10  WITHSCORES         //展示七日排行前十

排行榜.png

九、更多场景

  • 关注模型
  • 商品筛选
  • <附近的人>
  • <摇一摇>
  • <抢红包>
  • <附近的车>
  • <附近的餐馆>
  • 搜索自动补全
  • 布隆过滤器

十、参考

十一、最后

若有不足,敬请指正
虚心若愚,求知若渴

查看原文

赞 0 收藏 0 评论 0

MO_or 赞了文章 · 5月20日

SegmentFault 思否开源项目支持计划启动,为你的开源项目助力!

SegmentFault 思否开源项目支持计划

很高兴可以看到,开源正迎来最好的发展时期。

20 年前的开源项目,基本上是由个人开发者主导的。但随着开源精神的发展以及开源文化的普及,越来越多的企业与科技公司参与到了开源生态的建设当中。

但归根结底,开源更多的是一种社会化活动,很多的项目创意也是来自个人或者小型团队。个人有了兴趣,有了想法,并进而动手形成项目,而后建立社区,或者成立公司继续推进。这种模式将会持续存在,也是技术创新的一种健康和合理途径。所以游离于大公司外的开源项目和植根于大公司内的开源项目,会长期共存。

但根据社区部分开源作者的反馈,大部分的优质个人开源项目很难进行有效的传播推广。


为助力优质开源项目成长, SegmentFault 思否社区作为服务于开发者的技术社区,正式推出「SFOSSP - 思否开源项目支持计划」,我们希望借助社区的资源对开源项目进行相关的宣传推广,并作为一个长期项目助力开源事业的发展,与广大开发者共建开源新生态。

一、思否提供哪些永久的免费支持资源?

  1. 为开源项目在社区创建技术标签 ,如「Flutter」「TDengine」等;
  2. 思否编辑团队协助进行开源项目报道的文案整理优化;
  3. 思否资讯板块配合开源项目的相关发布报道;

二、思否可参与报道的内容类型有哪些?

  1. 开源项目介绍
  2. 开源项目重大版本发布
  3. 开源项目重要的里程碑事件
  4. 开源项目重要的技术突破
  5. 更多的报道需求,请与思否编辑团队进行深度沟通交流

三、对于开源项目有哪些要求?

  1. 个人项目、团队项目、商业开源项目都可以申请参与;
  2. 开源项目需要有明确的应用场景以及较高的项目质量;
  3. 开源项目的负责人要对提供的报道内容真实性负责。

有意向的开源项目负责人或团队成员,可通过邮箱提供相应的信息(开源项目地址、项目介绍、团队介绍、联系方式等),以便提升交流的效率。

  • 联系邮箱:pr@segmentfault.com
  • 思否开源项目申请表:申请表

clipboard.png

查看原文

赞 36 收藏 5 评论 19

MO_or 关注了用户 · 5月20日

SegmentFault @segmentfault

SegmentFault 社区管理媛 - 思否小姐姐

纯粹的技术社区离不开所有开发者的支持和努力 biubiu

更多技术内容与动态欢迎关注 @SegmentFault 官方微博与微信公众号!

点击添加思否小姐姐个人微信号

关注 83832

认证与成就

  • 获得 9 次点赞
  • 获得 1 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 1 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

  • IM

    该项目正在整合框架中,是笔者用于整合目前热门框架并简单实现其功能的练习地—— 目前已整合:Spring Boot、Mybatis、Druid、SLF4J—— 后续会整合:Redis、Netty、RabbitMQ、Spring Cloud、Nacos、Ribbon、Feign、Sentinel、Seata、GateWay—— 后续容器将使用:Jenkins、Docker—— 项目管理使用:SmartGit—— 协作管理使用:Tower

注册于 2019-04-29
个人主页被 1k 人浏览