1 簡介
判斷一個字符串是否包含某個特定子串是常見的場景,比如判斷一篇文章是否包含敏感詞匯、判斷日志是否有ERROR信息等。本文將介紹四種方法并進行性能測試。
2 四種方法
2.1 JDK原生方法String.indexOf
在String的函數中,提供了indexOf(subStr)方法,返回子串subStr第一次出現的位置,如果不存在則返回-1。例子如下:
//包含JavaassertEquals(7, “Pkslow Java”.indexOf(“Java”));//如果包含多個,返回第一次出現位置assertEquals(0, “Java Java”.indexOf(“Java”));//大小寫敏感assertEquals(-1, “Google Guava”.indexOf(“guava”));
2.2 JDK原生方法String.contains
最直觀判斷的方法是contains(subStr),返回類型為boolean,如果包含返回true,不包含則返回false。例子如下:
//包含JavaassertTrue(“code in Java”.contains(“Java”));//大小寫敏感,不包含GOassertFalse(“Let’s go”.contains(“GO”));//轉為大寫后包含assertTrue(“Let’s go”.toUpperCase().contains(“GO”));
實際上,String的contains方法是通過調用indexOf方法來判斷的,源碼如下:
public boolean contains(CharSequence s) { return indexOf(s.toString()) > -1;}
2.3 JDK原生正則匹配Pattern
通過強大的正則匹配來判斷,雖然有點殺雞用牛刀的感覺,但也不是不能用,例子如下:
Pattern pattern = Pattern.compile(“Java”);//包含JavaMatcher matcher1 = pattern.matcher(“Python, Java, Go, C++”);assertTrue(matcher1.find());//不包含JavaMatcher matcher2 = pattern.matcher(“Python, C, Go, Matlab”);assertFalse(matcher2.find());
2.4 Apache庫StringUtils.contains
Apache的commons-lang3提供許多開箱即用的功能,StringUtils就提供了許多與字符串相關的功能,例子如下:
//包含subassertTrue(StringUtils.contains(“String subString”, “sub”));//大小寫敏感assertFalse(StringUtils.contains(“This is Java”, “java”));//忽略大小寫assertTrue(StringUtils.containsIgnoreCase(“This is Java”, “java”));
3 性能對比
我們使用JMH工具來對四種方法進行性能測試,Maven引入代碼如下:
org.openjdk.jmh jmh-core ${openjdk.jmh.version} org.openjdk.jmh jmh-generator-annprocess ${openjdk.jmh.version}
測試代碼如下:
@BenchmarkMode(Mode.AverageTime)@OutputTimeUnit(TimeUnit.NANOSECONDS)public class StringContainsPerformanceTest { @State(Scope.Thread) public static class MyState { private String text = “If you want to be smart; read. If you want to be really smart; read a lot.”; Pattern pattern = Pattern.compile(“read”); } @Benchmark public int indexOf(MyState state) { return state.text.indexOf(“read”); } @Benchmark public boolean contains(MyState state) { return state.text.contains(“read”); } @Benchmark public boolean stringUtils(MyState state) { return StringUtils.contains(state.text, “read”); } @Benchmark public boolean pattern(MyState state) { return state.pattern.matcher(state.text).find(); } public static void main(String[] args) throws Exception { Options options = new OptionsBuilder() .include(StringContainsPerformanceTest.class.getSimpleName()) .threads(6) .forks(1) .warmupIterations(3) .measurementIterations(6) .shouldFailOnError(true) .shouldDoGC(true) .build(); new Runner(options).run(); }}
測試結果如下:
Benchmark Mode Cnt Score Error Unitscontains avgt 6 11.331 1.435 ns/opindexOf avgt 6 11.250 1.822 ns/oppattern avgt 6 101.196 12.047 ns/opstringUtils avgt 6 29.046 3.873 ns/op
最快的就是indexOf方法,其次是contains方法,二者應該沒有實際區(qū)別,contains是調用indexOf來實現的。Apache的StringUtils為第三方庫,相對慢一些。最慢的是使用了正則的Pattern的方法,這不難理解,正則引擎的匹配是比較耗性能的。
4 總結
本文介紹了判斷一個字符串是否包含某個特定子串的四種方法,并通過性能測試進行了對比。其中性能最好的是String的indexOf方法和contains方法,建議使用contains方法,性能好,跟indexOf相比,更直觀,更不容易犯錯。畢竟讓每個人時刻記住返回-1代表不存在也不是一件容易的事。
但是,使用indexOf和contains方法都需要注意做判空處理,這時StringUtils的優(yōu)勢就體現出來了。
如果本文對你有幫助,別忘記給我個3連 ,點贊,轉發(fā),評論,,咱們下期見。
收藏 等于白嫖,點贊才是真情。
原文 https://www.cnblogs.com/larrydpk/p/12459386.html