使用kotlin, springboot, mybatis构建web服务

搭建kotlin服务端项目时的问题

idea 无法识别基于 maven 的 kotlin项目, 一直报kotlin没有配置, 代码也一直在冒红

首先按照提示的指引去操作, 但是毫无用处

接下来在网上搜索怎么处理idea的提醒, 但是网上的信息均不可用

接下来在网上搜索怎么导入基于maven的kotlin项目, 但是网上只有创建的, 没有导入的

发现网上的大多数教程都是基于gradle的,于是放弃maven, 转战gradle

gradle构建使用idea一直卡顿, 使用命令一直报错

猜测是版本太低, 更新版本后就好了

打开idea后idea自己下载gradle最新包. 在idea指定gradle目录就好了

gradle下载依赖缓慢. 参照下面的文章配置阿里仓库就好了

更新gradle后, idea无法识别最新的配置, 还是使用旧的包. 是因为home没有更新, 重启机器即可

适配Mybatis时, 出现 Result Maps collection already contains value for com.autonavi.dao.impl.mapper.pms.DemandStatisticMapper.demandResultMap

是mybatis generator 生成了重复的mapper配置, 删掉, 重新生成就好

导入kotlin项目时, 把生成多个module的选项关掉, 使用本地的gradle包

参考

初始化项目
配置仓库
下载gradle
mybatis generator插件
项目demo

jvm_language.md

Scala:想解决Java表达能力不足的问题

Groovy:想解决Java语法过于冗长的问题

Clojure:想解决Java没有函数式编程的问题

Kotlin:想解决Java

java的堆内存模型

堆内存模型

新生带

eden 8

survivor1 1

survivor2 1

老年带

old

正常的垃圾回收

minorgc

比较频繁

jvm 每隔一段时间就会对eden 和某一块 survivor带进行minorgc, 清空该eden和survivor, 对于依然存活的对象会放在另一个survivor 中, 放不下的会放在 老年带old 中, 对在 survivor 中的 对象, 每经历一次 minorgc, 对象的年龄就增加1; 接下来的对象会放在已经有对象的那个survivor和old中

什么算垃圾:

有两种算法

不可触达算法

引用计数器 有循环引用的问题

进入老年带

一般年龄到 15的时候, 对象就会被老年带

如果是 大对象, 可能会提前进入老年带

如果survivor 内相同年龄大小的对象总和大于 它的一半,也会进入老年带

fullgc

fullgc / major gc 是对整个堆

比较耗时, 频率比较低, 要尽量避免 fullgc

老年带的回收

cmsgc 1.4 后引进, 高响应, 低吞吐率

对老年带的回收

案例

高并发条件下, 如果新生带足够大, 那么新生代的对象会在符合条件的时候进入老年带

经常老年带会进行 cms gc, 这时 很可能 老年带没空了, 就会触发 Concurrent mode failed

解决方案是增加 老年带, 更频发的触发 cmsgc

如果survivor不够, 容易间接触发Prommotion failed, 此刻可以增加 survivor 或者老年带

参考

一次频繁fullgc

jvm模型

fullgc时机

堆内存管理

cmsgc

ubuntu文件清理.md

大文件查看

cd /

sudo ls -a |sed -e ‘/^.$/d’ -e ‘/^..$/d’ | xargs -i sudo du -ms {}|sort -n |tee “/tmp/.capacity.date "+%Y-%m-%d_%H-%M-%S".log

大文件来源

  • thunderbird 回收站, 收件箱缓存

${HOME}/.thunderbird/gz2x0nma.default/ImapMail

echo “” > filename

  • idea应用日志

${HOME}/.IntelliJIdea2017.2/system/tomcat

find ./ -type f -iname “*.log” |xargs -i rm -rf {}

谈一谈String

从面试题说起

这行代码 String s = new string (“ddd”), 它创建了几个对象.

一个对象, 两个对象? 懵逼了吧, 我们细细说来

从常量谈起

java 中由 final 修饰的变量,就是常量, 有局部变量, 静态变量, 实例变量三种

常量池

  • 编译时的常量池

java编译后会生成class字节码, class字节码在魔数和版本号之后就是常量池, 常量池之后主要就是访问描述符号, 类父类, 接口的信息各种表了

在常量池里面存储两类信息, 字面量和符号引用. 字面量就是字符串, 符号引用 就是java类中各部分, 包括属性, 方法, 类, 接口的字符串描述. 在第一次使用某变量和方法时, 会从符号引用拿到对应的名字直接地址, 然后从方法区拿到对应的信息.

  • 运行时的常量池

java程序在运行时会有一个运行时常量池, 运行时常量池是方法区的一部分, 里面会加载编译时的静态常量池,加载的时机应该就是类生命周期中的连接中的解析阶段
解析阶段官方文档说法是将符号引用转化为直接引用,我的理解就是为java字节码中涉及到的各个信息在方法区分地址,再把符号引用指向对应的地址
加载
连接
准备 验证 解析
初始化

  • String的常量池

Jvm 为String设计了一个运行时的常量池, 也在方法区中, 每次创建新的字符串时, 会先从方法区中找, 没有就会新建一个放入方法区中的常量池, 有就会直接将引用指向那里.

  • java 语言层面的常量池

大部分包装类创建的时候如果是自动包装, 会调用 valueOf方法, 包装类内部会有一个静态类, 里面维护了一个数组做cache, 这样当有新的包装类对应的值需要创建对象的时候, 会先从内部的cache开始找, 有的话直接返回对应的引用, 如果没有在堆中生成新的对象

回到 String的创建

  • 谈一谈 String s = “ddd”

针对这种代码, java在编译器就会生成一个 ddd的字面量常量, 放入常量池中, 运行时, 类被加载时, 该常量和静态常量池的其他常量一起被放入方法区中

所以说 String s = “ddd”会创建一个对象, “ddd”是在类加载的时候创建的

  • 再谈 String s = new String(“ddd”);

首先, 编译期在字节码中会有一个常量池, 常量池前面一部分是字面量, ddd作为字面量会被保存在其中, 然后在运行时,
方法区中存在运行时常量池, 静态常量池中的内容会在类加载的时候存入方法区中的常量池中, 这个时候建立的第一个字面量对象ddd,
允许到该代码时创建第二个对象,放在堆中,但实际上还是指向的同一个字节数组

  • 方法区的回收

默认是不会开启回收的, 需要加参数开启

数字转语音问题

概述

String numberToVoice(int number) 的小测试. eg: 12345 整数转读音成 一万二千三百四十五, 这个题目美团要求是20分钟做完且能跑通, 不会做就不要去面试了.

解决第一阶段, 风风火火完成需求

我开始一看这个题目, 感觉很简单啊, 五位数, 加一个位描述, 对应 万 千 百 十 个位, 建立一个对应的 table就可以了

1
2
3
4
5
6
7
8
9
private static final Map<Integer, String> numberVoiceMap = ImmutableMap.<Integer, String>builder()
.putAll(ImmutableMap.of(
10000, "万"
, 1000, "千"
, 100, "百"
, 10, "十"
, 1, ""
))
.build();

然后每个数, 0~9 同样建立一个table

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private static final Map<Integer, String> numberMap = ImmutableMap.<Integer, String>builder()
.putAll(ImmutableMap.of(
0, "零"
, 1, "一"
, 2, "二"
, 3, "三"
, 4, "四"
))
.putAll(ImmutableMap.of(
5, "五"
, 6, "六"
, 7, "七"
, 8, "八"
, 9, "九"
))
.build();

接下来, 直接 循环 numberVoiceMap 拿到对应每位的数 和 位描述 即可. 然后啪啪啪就把代码写出来了, 加上测试案例也大概才华了16分钟左右, 而且测试类完美通过, 下面贴下代码

  • NumberUtils
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    package com.luozi.api;

    import com.google.common.collect.ImmutableMap;

    import java.util.Map;
    import java.util.Objects;

    /**
    * Created by luoziyihao on 6/19/17.
    */
    public class NumberUtils {

    private static final Map<Integer, String> numberVoiceMap = ImmutableMap.<Integer, String>builder()
    .putAll(ImmutableMap.of(
    10000, "万"
    , 1000, "千"
    , 100, "百"
    , 10, "十"
    , 1, ""
    ))
    .build();

    private static final Map<Integer, String> numberMap = ImmutableMap.<Integer, String>builder()
    .putAll(ImmutableMap.of(
    0, "零"
    , 1, "一"
    , 2, "二"
    , 3, "三"
    , 4, "四"
    ))
    .putAll(ImmutableMap.of(
    5, "五"
    , 6, "六"
    , 7, "七"
    , 8, "八"
    , 9, "九"
    ))
    .build();

    private static final int high = 100000;
    /**
    * 整数转读音 只支持到万位
    *
    * @param num
    * @return
    */
    public static String numberToVoice(int num) {
    if (num >= high) {
    throw new IllegalStateException("this method did't support number greater then " + high);
    }
    StringBuilder builder = new StringBuilder();
    for (Map.Entry<Integer, String> entry : numberVoiceMap.entrySet()) {
    int count = num / entry.getKey();
    if (count >= 1) {
    builder.append(numberMap.get(count))
    .append(entry.getValue());
    }
    num = num % entry.getKey();

    }
    return builder.toString();
    }

    }

  • NumberUtilsTest
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    package com.luozi.api;

    import org.junit.Assert;
    import org.junit.Test;

    import static org.junit.Assert.*;

    /**
    * Created by luoziyihao on 6/19/17.
    */
    public class NumberUtilsTest {

    @Test
    public void numberToVoice() throws Exception {
    Assert.assertEquals("一", NumberUtils.numberToVoice(1));
    Assert.assertEquals("一十一", NumberUtils.numberToVoice(11));
    Assert.assertEquals("一百一十一", NumberUtils.numberToVoice(111));
    Assert.assertEquals("一千一百一十一", NumberUtils.numberToVoice(1111));
    Assert.assertEquals("一万二千三百四十", NumberUtils.numberToVoice(12340));
    Assert.assertEquals("一万二千三百四十五", NumberUtils.numberToVoice(12345));
    }
    }

解决第二阶段, 加上 0 的处理

上面的代码貌似可以了, 可是突然我想到, 上面的数字咋没有出现 0啊, 万一出现12004这种数怎么办, 代码中没有做这种处理, 肯定有问题. 于是开始改代码, 中间几多艰辛在此不再细表. 反正是又花了二十多分钟, 才改完并测试通过, 好吧, 我承认我没有通过测试. 下面重新贴一下第二版代码

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    package com.luozi.api;

    import com.google.common.collect.ImmutableMap;

    import java.util.Map;
    import java.util.Objects;

    /**
    * Created by luoziyihao on 6/19/17.
    */
    public class NumberUtils {

    private static final Map<Integer, String> numberVoiceMap = ImmutableMap.<Integer, String>builder()
    .putAll(ImmutableMap.of(
    10000, "万"
    , 1000, "千"
    , 100, "百"
    , 10, "十"
    , 1, ""
    ))
    .build();

    private static final Map<Integer, String> numberMap = ImmutableMap.<Integer, String>builder()
    .putAll(ImmutableMap.of(
    0, "零"
    , 1, "一"
    , 2, "二"
    , 3, "三"
    , 4, "四"
    ))
    .putAll(ImmutableMap.of(
    5, "五"
    , 6, "六"
    , 7, "七"
    , 8, "八"
    , 9, "九"
    ))
    .build();

    private static final int high = 100000;
    /**
    * 整数转读音 只支持到万位
    *
    * @param num
    * @return
    */
    public static String numberToVoice(int num) {
    if (num >= high) {
    throw new IllegalStateException("this method did't support number greater then " + high);
    }
    StringBuilder builder = new StringBuilder();
    for (Map.Entry<Integer, String> entry : numberVoiceMap.entrySet()) {
    int count = num / entry.getKey();
    if (count >= 1) {
    builder.append(numberMap.get(count))
    .append(entry.getValue());
    } else if (checkIsAppendZero(builder, entry)) {
    builder.append(numberMap.get(count));
    }
    num = num % entry.getKey();

    }
    CheckAndRemoveSpareZero(builder);
    return builder.toString();
    }

    private static final int zero = 0;
    private static void CheckAndRemoveSpareZero(StringBuilder builder) {
    int length = builder.length();
    while (length > 1 && getLastChar(builder).equals(numberMap.get(zero))) {
    length = builder.length();
    if (Objects.equals(getLastChar(builder), numberMap.get(zero)) && length > 1) {
    builder.deleteCharAt(length - 1);
    }
    }

    }

    private static String getLastChar(StringBuilder builder) {
    int length = builder.length();
    if (length >= 1){
    return builder.charAt(length - 1) + "";
    } else {
    return "";
    }
    }

    private static boolean checkIsAppendZero(StringBuilder builder, Map.Entry<Integer, String> entry) {
    int length = builder.length();
    return (length > 0 && !Objects.equals(getLastChar(builder), numberMap.get(zero)))
    || entry.getKey() == 1;
    }
    }

  • NumberUtilsTest
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    package com.luozi.api;

    import org.junit.Assert;
    import org.junit.Test;

    import static org.junit.Assert.*;

    /**
    * Created by luoziyihao on 6/19/17.
    */
    public class NumberUtilsTest {

    @Test
    public void numberToVoice() throws Exception {
    Assert.assertEquals("一", NumberUtils.numberToVoice(1));
    Assert.assertEquals("一十一", NumberUtils.numberToVoice(11));
    Assert.assertEquals("一百一十一", NumberUtils.numberToVoice(111));
    Assert.assertEquals("一千一百一十一", NumberUtils.numberToVoice(1111));
    Assert.assertEquals("一万二千三百四十", NumberUtils.numberToVoice(12340));
    Assert.assertEquals("一万二千三百四十五", NumberUtils.numberToVoice(12345));

    Assert.assertEquals("一万零四十五", NumberUtils.numberToVoice(10045));
    Assert.assertEquals("零", NumberUtils.numberToVoice(0));
    Assert.assertEquals("一十", NumberUtils.numberToVoice(10));
    Assert.assertEquals("一百", NumberUtils.numberToVoice(100));
    Assert.assertEquals("一百零一", NumberUtils.numberToVoice(101));

    }

    }

解决第三阶段, 支持所有 int 整数

其实在一开始写这个需求的时候, 就默认忽视了一点, 以为这个数处理的最大位数是 5位数, 但实际上人家代码需求里面写的请清楚楚明明白白的是 整数转读音, java里面的整数是 4个字节的, 打开python算一下, 2**31 结果是 2147483648, 10位数,对应二十一亿四千七百八十三三千六百四十八 ,上面的实现肯定处理不了这个数.

好吧,怎么改呢, 仔细看了看中文描述, 发现除了多了亿这两个描述, 每个四位的处理基本上都一样, 那就四位四位地读吧, 延续前面的思路, 定义了新的table

1
2
3
4
5
6
private static final Map<Integer, String> BIGNUMBER_VOICE_MAP = ImmutableMap.<Integer, String>builder()
.putAll(ImmutableMap.of(
100000000, "亿"
, 10000, "万"
))
.build();

前面的方法重构成处理四位数的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private static final int ZERO_CHECK_NUMBER = 1000;
private static StringBuilder processForFourBit(int num) {
StringBuilder builder = new StringBuilder();
if (num < ZERO_CHECK_NUMBER) { // 是否需要在第一位添零
builder.append(NUMBER_MAP.get(zero));
}
if (num >= HIGH) {
throw new IllegalStateException("this method did't support number greater then " + HIGH);
}
for (Map.Entry<Integer, String> entry : NUMBER_VOICE_MAP.entrySet()) { // 拿到每一位的数 和 值
int count = num / entry.getKey();
if (count >= 1) {
builder.append(NUMBER_MAP.get(count))
.append(entry.getValue());
} else if (checkIsAppendZero(builder, entry)) {
builder.append(NUMBER_MAP.get(count));
}
num = num % entry.getKey();

}
CheckAndRemoveSpareLastZero(builder);
return builder;
}

然后在处理四位的 前面又套一层

1
2
3
4
5
6
7
8
9
10
11
12
13
StringBuilder builder = new StringBuilder();

for (Map.Entry<Integer, String> entry : BIGNUMBER_VOICE_MAP.entrySet()) {
int count = num / entry.getKey();
num = num % entry.getKey();
if (count > 0) {
builder.append(processForFourBit(count)) // 数字按照四位分组处理
.append(entry.getValue());
}

}

builder.append(processForFourBit(num));

最后加上测试案例, 执行完美通过, 可是这个过程又花了我二十多分钟, 好吧, 我承认我离美团越來越远了, 哈哈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.luozi.api;

import org.junit.Assert;
import org.junit.Test;

import static org.junit.Assert.*;

/**
* Created by luoziyihao on 6/19/17.
*/
public class NumberUtilsTest {

@Test
public void numberToVoice() throws Exception {
Assert.assertEquals("一", NumberUtils.numberToVoice(1));
Assert.assertEquals("一十一", NumberUtils.numberToVoice(11));
Assert.assertEquals("一百一十一", NumberUtils.numberToVoice(111));
Assert.assertEquals("一千一百一十一", NumberUtils.numberToVoice(1111));
Assert.assertEquals("一万二千三百四十", NumberUtils.numberToVoice(12340));
Assert.assertEquals("一万二千三百四十五", NumberUtils.numberToVoice(12345));

Assert.assertEquals("一万零四十五", NumberUtils.numberToVoice(10045));
Assert.assertEquals("零", NumberUtils.numberToVoice(0));
Assert.assertEquals("一十", NumberUtils.numberToVoice(10));
Assert.assertEquals("一百", NumberUtils.numberToVoice(100));
Assert.assertEquals("一百零一", NumberUtils.numberToVoice(101));


Assert.assertEquals("一亿零三百万零三百零一", NumberUtils.numberToVoice(103000301));
Assert.assertEquals("二十一亿零三百万零三百零一", NumberUtils.numberToVoice(2103000301));
Assert.assertEquals("二十一亿零三百零一", NumberUtils.numberToVoice(2100000301));
Assert.assertEquals("二十一亿零三百", NumberUtils.numberToVoice(2100000300));
Assert.assertEquals("二十一亿", NumberUtils.numberToVoice(2100000000));
Assert.assertEquals("一百零一", NumberUtils.numberToVoice(101));

}

}

下面贴一下实现类的完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package com.luozi.api;

import com.google.common.collect.ImmutableMap;

import java.util.Map;
import java.util.Objects;

/**
* Created by luoziyihao on 6/19/17.
*/
public class NumberUtils {

private static final Map<Integer, String> BIGNUMBER_VOICE_MAP = ImmutableMap.<Integer, String>builder()
.putAll(ImmutableMap.of(
100000000, "亿"
, 10000, "万"
))
.build();

private static final Map<Integer, String> NUMBER_VOICE_MAP = ImmutableMap.<Integer, String>builder()
.putAll(ImmutableMap.of(
1000, "千"
, 100, "百"
, 10, "十"
, 1, ""
))
.build();

private static final Map<Integer, String> NUMBER_MAP = ImmutableMap.<Integer, String>builder()
.putAll(ImmutableMap.of(
0, "零"
, 1, "一"
, 2, "二"
, 3, "三"
, 4, "四"
))
.putAll(ImmutableMap.of(
5, "五"
, 6, "六"
, 7, "七"
, 8, "八"
, 9, "九"
))
.build();

private static final int HIGH = 10000;

/**
* 整数转读音
*
* @param num
* @return
*/
public static String numberToVoice(int num) {
StringBuilder builder = new StringBuilder();

for (Map.Entry<Integer, String> entry : BIGNUMBER_VOICE_MAP.entrySet()) {
int count = num / entry.getKey();
num = num % entry.getKey();
if (count > 0) {
builder.append(processForFourBit(count)) // 数字按照四位分组处理
.append(entry.getValue());
}

}

builder.append(processForFourBit(num));
CheckAndRemoveSpareFirstZero(builder);
CheckAndRemoveSpareLastZero(builder);
return builder.toString();
}

private static void CheckAndRemoveSpareFirstZero(StringBuilder builder) {
int length = builder.length();
while (length > 1 && getFirstChar(builder).equals(NUMBER_MAP.get(zero))) {
length = builder.length();
if (Objects.equals(getFirstChar(builder), NUMBER_MAP.get(zero)) && length > 1) {
builder.deleteCharAt(zero);
}
}

}

private static final int ZERO_CHECK_NUMBER = 1000;
private static StringBuilder processForFourBit(int num) {
StringBuilder builder = new StringBuilder();
if (num < ZERO_CHECK_NUMBER) { // 是否需要在第一位添零
builder.append(NUMBER_MAP.get(zero));
}
if (num >= HIGH) {
throw new IllegalStateException("this method did't support number greater then " + HIGH);
}
for (Map.Entry<Integer, String> entry : NUMBER_VOICE_MAP.entrySet()) { // 拿到每一位的数 和 值
int count = num / entry.getKey();
if (count >= 1) {
builder.append(NUMBER_MAP.get(count))
.append(entry.getValue());
} else if (checkIsAppendZero(builder, entry)) {
builder.append(NUMBER_MAP.get(count));
}
num = num % entry.getKey();

}
CheckAndRemoveSpareLastZero(builder);
return builder;
}

private static final int zero = 0;

private static void CheckAndRemoveSpareLastZero(StringBuilder builder) {
int length = builder.length();
while (length > 1 && getLastChar(builder).equals(NUMBER_MAP.get(zero))) {
length = builder.length();
if (Objects.equals(getLastChar(builder), NUMBER_MAP.get(zero)) && length > 1) {
builder.deleteCharAt(length - 1);
}
}
}

private static String getLastChar(StringBuilder builder) {
int length = builder.length();
if (length >= 1) {
return builder.charAt(length - 1) + "";
} else {
return "";
}
}

private static String getFirstChar(StringBuilder builder) {
int length = builder.length();
if (length >= 1) {
return builder.charAt(0) + "";
} else {
return "";
}
}

private static boolean checkIsAppendZero(StringBuilder builder, Map.Entry<Integer, String> entry) {
int length = builder.length();
return (length >= 1 && !Objects.equals(getLastChar(builder), NUMBER_MAP.get(zero)))
|| entry.getKey() == 1;
}


}

解决第四阶段, 重构, 代码洁癖狂开始扫垃圾了

不得不承认, 上面某些代码是很丑陋的, 比如将 char 转成String 再比较, zero的描述从map里面取, 完全是多余的逻辑, 整个代码逻辑略显混乱, 方法和参数名都取的不好…

代码未优化完毕, 暂见https://github.com/luoziyihao/java-practice/blob/master/api/src/main/java/com/luozi/api/NumberUtils.java

字符串分段逆序

字符串分段逆序问题, 给一个字符串 aaa–bb-ccc, 转变成 ccc-bb-aaa

  • 思路

目的, 向下分析,问自己问题, 导出解决方案

  • 把字符串分组
    处理字节数组即可, 分组的要点在于相邻的元素

  • 字符串逆序拼接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package com.luozi.string;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* Created by luoziyihao on 6/22/17.
*/
public class StringReverser {
/**
* 使用字节数组的处理方式
* 先尝试理出大致思路, 找一个方向
* 在构思算法的关键点, 可以划出来
* 再边写边想
*/
public String reverseStringBySplitChar(String src, char split){
//校验src
//循环处理字符数组, 将里面的char按照 split分别放在好几个String中
//关键点是比较相邻的两个字符
char[] arrs = src.toCharArray();
List<String> lists = new ArrayList<String>();
int length = arrs.length;
StringBuilder builder = new StringBuilder();
for(int i = 0; i < length; i++) {
char nowChar = arrs[i];
if (i == 0) {
builder.append(nowChar);
continue;
}
char lastChar = arrs[i-1];

// 在循环中拼装出具体的子串, 子串的结束时机用isSplitStringEnd控制
boolean isSplitAfterString = lastChar != split && nowChar == split;
boolean isStringAfterSplit = lastChar == split && nowChar != split;
if (isSplitAfterString || isStringAfterSplit) {
lists.add(builder.toString());
builder = new StringBuilder();
}
builder.append(nowChar);

}
lists.add(builder.toString());
Collections.reverse(lists);
return appendString(lists);
}

private String appendString(List<String> lists) {
StringBuilder builder = new StringBuilder();
for (String str : lists) {
builder.append(str);
}
return builder.toString();

}
}