Java 使用Lambda表达式使用HashMap替换字符串中的字符

Java 使用Lambda表达式使用HashMap替换字符串中的字符,java,lambda,Java,Lambda,所以我正在做一个项目,在这个项目中,我必须将一个包含希腊字母的字符串转换成一个包含这个字母的英语表示形式的字符串。因此,希腊语α将变成α,Α将变成α 我创建了一个HashMap,它具有从Unicode字符到普通字符串的适当转换 我使用了一个简单的For循环来检查输入String中的Char是否是HashMap中的键,如果是,我将使用StringBuilder附加其替换项。以下是我用于执行此操作的代码: char[] ca = snippet.toCharArray(); Stri

所以我正在做一个项目,在这个项目中,我必须将一个包含希腊字母的字符串转换成一个包含这个字母的英语表示形式的字符串。因此,希腊语
α
将变成
α
Α
将变成
α

我创建了一个HashMap,它具有从Unicode字符到普通字符串的适当转换

我使用了一个简单的
For
循环来检查输入
String
中的
Char
是否是
HashMap
中的
键,如果是,我将使用
StringBuilder
附加其替换项。以下是我用于执行此操作的代码:

char[] ca = snippet.toCharArray();
        StringBuilder out = new StringBuilder();
        for (char c : ca) {
            if (GREEK_LETTER_DICT.containsKey(Character.toString(c))) {
                out.append( GREEK_LETTER_DICT.get(Character.toString(c)));
            } else {
                out.append(c);
            }
        }
    return out.toString();
这是一个公共静态方法,以
String
作为输入。 我想知道的是,是否可以对lambda表达式执行相同的操作?我已经在
字符串
中找到了一些替代
字符
的解决方案,但它们不使用
HashMap
/
字典

我明白为了使用lambda表达式而将其转换为lambda表达式是完全没有用的,但是因为我还有另外7个函数将我的代码缩短了近60%,我想看看是否有可能在“一行”代码中实现这一点。通过这种方式,我可以减少使用的单独方法的数量,并获得更干净的代码

到目前为止,我已经找到了一种将
字符串
转换为
的方法,使用:

String.chars()
然后使用将此
IntStream
转换为

.mapToObj(ch -> (char) ch)
.filter(ch -> (GREEK_LETTER_DICT.containsKey(ch)))
并进行过滤,以查看
字符是否位于
哈希映射中

.mapToObj(ch -> (char) ch)
.filter(ch -> (GREEK_LETTER_DICT.containsKey(ch)))
问题在于我不能做到这一点

  • 如果原始
    字符
    不在
    哈希映射
  • 字符
    替换为
    哈希映射中的字符串
  • 因此,在这两点上的任何帮助都是非常感谢的。我发现,有时我的想法是错误的,因为我不应该查看
    字符串中的
    字符是否等于选项列表中的
    字符,而是应该检查该选项列表是否返回正的
    索引。所以这个(伪代码):

    “StringWithOptions.indexOf('characterLiteral')

    与此相反:


    Character.equals(“其中一个”)
    我会这样做:

    str
        .chars()
        .forEach(
            character -> out.append(
                GREEK_LETTER_DICT.getOrDefault(Character.toString(c), c)
            )
        );
    
    因此,使用来自的代码,我能够让它工作。生成的代码现在返回一个
    字符串
    ,返回正确的结果,并通过所有单元测试

    这是生成的代码:

        return snippet.chars()
                .mapToObj(c -> (char) c)
                .collect(Collector.of(StringBuilder::new,
                        (stringBuilder, c) -> stringBuilder.append(GREEK_LETTER_DICT.getOrDefault(c,c.toString())),
                        StringBuilder::append,
                        StringBuilder::toString));
    
    来自的代码有一个问题,HashMap使用,而不是。因此,我必须更改
    #getOrDefault
    的参数。将它与
    .mapToObj(c->(char)c)
    结合使用,就成功了

    现在让我们看看我是否可以改变这一点:

    (stringBuilder, c) -> stringBuilder.append(GREEK_LETTER_DICT.getOrDefault(c,c.toString())),
                            StringBuilder::append
    
    类似于
    StringBuilder::append(希腊文字母DICT.getOrDefault(c,Character.toString(c))

    如何:

    public static String replaceGreekLetters(String snippet) {
        return snippet
                .chars()
                .mapToObj(c -> (char) c)
                .map(c -> GREEK_LETTER_DICT.getOrDefault(c, c.toString()))
                .collect(Collectors.joining());
    }
    

    使用蒸汽有几种很好的解决方案。我更喜欢简单的方案:

    • 避免从字符到字符串的转换
    • 避免在流管道之外使用StringBuffer
    • 使用预定义收集器

    基于所讨论的代码
    str.chars().forEach(character->out.append(希腊文字母_DICT.getOrDefault(character.toString(c),c));
    很快;-)感谢您的回复。有了这段代码,我们就可以让它工作了。我会把它挂在这里。我不得不对代码做一些修改。我建议你把这句话写进答案里。
    map
    不是更好吗?这样OP就根本不需要StringBuilder了?这只是使用streams的借口。如果每个循环都将是有状态的,则对其使用法线。这比操作状态变量(Stringbuilder)要好,它提供了更好的并行性:)@niceman此过滤器可以并行执行。您建议不要使用
    StringBuilder
    吗?@NathanvanDalen是的,如果不将
    c.toString()
    添加到
    getOrDefault
    的第一个参数中,我将无法实现此功能。我认为
    mapToObj
    应该映射到
    String
    @4Castle我的首字母TS包含一个错误,其中
    希腊文字母containsKey(Character.toString(c))
    应该是
    希腊文字母containsKey(c)
    ,因为HashMap是,但我忘了更改它@xehpuk的代码是正确的。OP使用的是
    Map
    。好的解决方案!但是这个线程安全吗?我想这是因为
    String
    本身就是。这确实是一个非常优雅的解决方案,只需3行代码。与我之前的10行相比,可读性有很大的不同@4castle:我可以轻松切换回
    。@NathanvanDalen是的,它是线程安全的。它的功能与其他解决方案非常相似。您可以使用
    Pattern.compile(“”).splitAsStream(original)
    而不是
    Arrays.stream(original.split(“”))来避免创建临时数组。MuttoObj[cto>字符> toStand((char)c)效率更高……你认为这比你原来的循环短/简单吗?