10

I have a method to remove some characters from a string. Is there a better way to do this using java 8?

public String filter(String test) {
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < test.length(); i++) {
        if (MYCOLLECTION.contains(test.charAt(i))) {
            builder .append(test.charAt(i));
        }
    }
    return builder .toString();
}
0

4 Answers 4

5

How about this:

Set<Character> filter = new HashSet<>(Arrays.asList('a','b','c'));
String filtered = "abcdefga".chars ()
                            .filter(i -> filter.contains((char) i))
                            .mapToObj(i -> "" + (char) i)
                            .collect(Collectors.joining());
System.out.println (filtered);

Output:

abca

Note: filter serves the same purpose as your MYCOLLECTION - I just gave it a more meaningful name and used a Set for better performance of contains.

It could have been cleaner if there was a CharStream (i.e. stream of primitive chars), so I wouldn't have to use an IntStream.

Sign up to request clarification or add additional context in comments.

8 Comments

You can use .mapToObj(Character::toString) over .mapToObj(i -> "" + (char) i), right?
@Michael It would have to be .mapToObj(i -> Character.toString((char) i)). The suggested method reference doesn't pass compilation.
@Michael your variant works on ideone, because Character.toString(int) has been added in Java 11.
This stream variant doesn’t look like an improvement over the original loop code to me. And it surely doesn’t add to performance.
@Naman like filtered = inputString.replaceAll( filter.stream().map(Object::toString).collect(Collectors.joining("", "[^", "]")),"")? It only works when the characters have no special meaning (or you’d need additional efforts). Unless the filter characters are constant, nothing can beat the simple loop solution…
|
1

"Better" by what metric? Here's how I would write it

final String filtered = test.chars()
    .mapToObj(chr -> (char) chr)    // IntStream -> Stream<Character>
    .filter(MYCOLLECTION::contains)
    .collect(
        Collector.of(StringBuilder::new, StringBuilder::append, StringBuilder::append, StringBuilder::toString)
    );

The collector is a bit ugly, I would probably extract it to its own method

private static Collector<Character, StringBuilder, String> characterCollector()
{
    return Collector.of(
        StringBuilder::new,
        StringBuilder::append,
        StringBuilder::append,
        StringBuilder::toString
    );
}

Then call this instead

.collect(characterCollector())

Comments

1

If you're open to using a third-party library, the following will work using Java 8 with Eclipse Collections.

CharSet set = CharSets.immutable.with('a', 'b', 'c');
CharAdapter chars = Strings.asChars("a1b2c3");
String string = chars.select(set::contains).toString();
Assert.assertEquals("abc", string);

Eclipse Collections has support for primitive collections so there is no need to box char values as Character instances.

You can also exclude instead of include characters using the method named reject which is the opposite of select.

CharSet set = CharSets.immutable.with('a', 'b', 'c');
CharAdapter chars = Strings.asChars("a1b2c3");
String include = chars.select(set::contains).toString();
String exclude = chars.reject(set::contains).toString();
Assert.assertEquals("abc", include);
Assert.assertEquals("123", exclude);

Note: I am a committer for Eclipse Collections.

Comments

1

Here is a very simple way using Regex

var string = "what ever you want!";

final var charSet = "".,;:!@";

final var stringResult = string.replaceAll("[" + charSet + "]", "");

>> ""what ever you want"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.