saudações
Examinando o material acumulado, java.lang.String
decidi fazer uma pequena seleção de exemplos do uso eficaz (e não tanto).
Qualquer conversão de linha gera uma nova linha
Este é um dos principais mitos sobre as linhas. De fato, esse nem sempre é o caso. Suponha que tenhamos uma string contendo apenas letras minúsculas:
var str = "str";
Agora este código
jshell> var str = "str";
jshell> System.out.println(str.toLowerCase() == str);
irá produzir
true
Em outras palavras, aqui a chamada toLowerCase()
retornou a linha na qual foi chamada. E embora esse comportamento não esteja descrito na documentação, o código StringLatin1.toLowerCase()
não deixa dúvidas (aqui e abaixo está o código de https://hg.openjdk.java.net/jdk/jdk/ ):
public static String toLowerCase(String str, byte[] value, Locale locale) {
if (locale == null) {
throw new NullPointerException();
}
int first;
final int len = value.length;
for (first = 0 ; first < len; first++) {
int cp = value[first] & 0xff;
if (cp != CharacterDataLatin1.instance.toLowerCase(cp)) {
break;
}
}
if (first == len)
return str;
}
: , . , , , String.trim()
String.strip()
:
public String trim() {
String ret = isLatin1() ? StringLatin1.trim(value)
: StringUTF16.trim(value);
return ret == null ? this : ret;
}
public String strip() {
String ret = isLatin1() ? StringLatin1.strip(value)
: StringUTF16.strip(value);
return ret == null ? this : ret;
}
:
boolean isUpperCase = name.toUpperCase().equals(name);
- StringUtils
, ( ""). / /, , name.toUpperCase()
name
, ?
boolean isUpperCase = name.toUpperCase() == name;
, , String.toUpperCase()
. ( , ) o.a.c.l.StringUtils.isAllUpperCase()
.
boolean eq = aString.toUpperCase().equals(anotherString);
boolean eq = aString.equalsIgnoreCase(anotherString);
, "" , "".
String.toLowerCase()
String.toLowerCase()
/ String.toUpperCase()
, . :
boolean isEmpty = someStr.toLowerCase().isEmpty();
, . , / . , isEmpty()
true
. false
, . . 1 , .
, :
boolean isEmpty = someStr.isEmpty();
. String.isEmpty()
:
public boolean isEmpty() {
return value.length == 0;
}
int len = someStr.toLowerCase().length();
int len = someStr.length();
, ?
String s = "!";
String s = "!";
, , . . — . , toLowerCase()
/ toUpperCase()
, . , . , :
@Test
void toLowerCase() {
String str = "\u00cc";
assert str.length() == 1;
String strLowerCase = str.toLowerCase(new Locale("lt"));
assert strLowerCase.length() == 3;
}
, : " ?" 1 , ( — 6 (!) ). :
public String toLowerCase(Locale locale) {
}
:
public static String toLowerCase(String str, byte[] value, Locale locale) {
String lang = locale.getLanguage();
if (lang == "tr" || lang == "az" || lang == "lt") {
return toLowerCaseEx(str, value, first, locale, true);
}
}
, , :)
1 — String.substring(n, n+1)
— , , , 1. :
boolean startsWithUnderline = message.substring(0, 1).equals("_");
boolean startsWithUnderline = message.charAt(0) == '_';
, . :
String s = "xxx" + name.substring(n, n + 1);
String s = "xxx" + name.charAt(n);
, . . . , .
— :
boolean startsWithUrl = content.substring(index, index + 4).equals("url(");
boolean startsWithUrl = content.startsWith("url(", index);
. , ( ):
private String findPerClause(String str) {
str = str.substring(str.indexOf('(') + 1);
str = str.substring(0, str.length() - 1);
return str;
}
, , :
( , )
-->
,
, , :
private String findPerClause(String str) {
int beginIndex = str.indexOf('(') + 1;
int endIndex = str.length() - 1;
return str.substring(beginIndex, endIndex);
}
, :
int idx = path.substring(2).indexOf('/');
, String.indexOf(int ch, int fromIndex)
, :
int idx = path.indexOf('/', 2);
. , '/'
2, . . :
int idx = name.indexOf('/', 2);
if (pos != -1) {
idx -= 2;
}
, .
JDK. ,
someStr.substring(n, n);
, n
:
public String substring(int beginIndex, int endIndex) {
int length = length();
checkBoundsBeginEnd(beginIndex, endIndex, length);
int subLen = endIndex - beginIndex;
if (beginIndex == 0 && endIndex == length) {
return this;
}
return isLatin1() ? StringLatin1.newString(value, beginIndex, subLen)
: StringUTF16.newString(value, beginIndex, subLen);
}
public static String newString(byte[] val, int index, int len) {
return new String(Arrays.copyOfRange(val, index, index + len), LATIN1);
}
beginIndex
endIndex
subLen
0, StringLatin1.newString()
. , :
public static String newString(byte[] val, int index, int len) {
if (len == 0) {
return "";
}
return new String(Arrays.copyOfRange(val, index, index + len), LATIN1);
}
StringLatin1.stripLeading() / stripTrailing()
StringUTF16
. .
, :
public static String stripLeading(byte[] value) {
int left = indexOfNonWhitespace(value);
if (left == value.length) {
return "";
}
return (left != 0) ? newString(value, left, value.length - left) : null;
}
value.length == 0
. left == value.length
newString
,
public static String stripLeading(byte[] value) {
int left = indexOfNonWhitespace(value);
return (left != 0) ? newString(value, left, value.length - left) : null;
}
null
! String.stripLeading()
, this
, . , . :
boolean b= new String("").stripLeading() == "";
boolean b= new String("").stripLeading() == "";
, ?
!
, :
@Warmup(iterations = 10, time = 1)
@Measurement(iterations = 10, time = 1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(value = 3, jvmArgsAppend = {"-Xms4g", "-Xmx4g", "-XX:+UseParallelGC"})
public class SubstringBenchmark {
private static final String str = "Tolstoy";
@Benchmark
public String substring() {
return str.substring(1, 1);
}
}
:
Mode Score Error Units
substring avgt 5.8 ± 0.066 ns/op
substring:·gc.alloc.rate avgt 4325.9 ± 47.259 MB/sec
substring:·gc.alloc.rate.norm avgt 40.0 ± 0.001 B/op
substring:·gc.churn.G1_Eden_Space avgt 4338.8 ± 86.555 MB/sec
substring:·gc.churn.G1_Eden_Space.norm avgt 40.1 ± 0.647 B/op
substring:·gc.churn.G1_Survivor_Space avgt 0.0 ± 0.003 MB/sec
substring:·gc.churn.G1_Survivor_Space.norm avgt ≈ 10⁻⁴ B/op
substring:·gc.count avgt 557.0 counts
substring:·gc.time avgt 387.0 ms
substring avgt 2.4 ± 0.172 ns/op
substring:·gc.alloc.rate avgt 0.0 ± 0.001 MB/sec
substring:·gc.alloc.rate.norm avgt ≈ 10⁻⁵ B/op
substring:·gc.count avgt ≈ 0 counts
, String.substring(n, n)
, .
, , , , . , AnnotationMetadataReadingVisitor-:
MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValAsStr) {
String annotatedElement = "class '" + getClassName() + "'";
for (AnnotationAttributes raw : attributes) {
for (Map.Entry<String, Object> entry : convertClassValues(
"class '" + getClassName() + "'", classLoader, raw, classValAsStr).entrySet()) {
allAttributes.add(entry.getKey(), entry.getValue());
}
}
return allAttributes;
}
A expressão "class '" + getClassName() + "'"
será a mesma e não queremos criar a mesma linha em um loop duplo, portanto, é melhor criá-la 1 vez fora do loop. Anteriormente, capturar esses exemplos era uma questão de chance: eu encontrei esse que falhou com êxito dentro da fonte ao depurar meu aplicativo. Agora, graças ao IDEA-230889, isso pode ser automatizado. Obviamente, está longe de ser sempre a criação de uma nova linha em um loop, independentemente da passagem, mas mesmo nesses casos, podemos distinguir aqueles em que há uma parte constante duradoura:
public static String uniqueBeanName(String beanName, BeanDefinitionRegistry registry) {
String id = beanName;
int counter = -1;
while (counter == -1 || registry.containsBeanDefinition(id)) {
counter++;
id = beanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
}
return id;
}
Aqui, o prefixo é beanName + GENERATED_BEAN_NAME_SEPARATOR
sempre o mesmo, portanto, ele pode ser trazido para fora.
Isso é tudo, escreva seus exemplos nos comentários - nós cobriremos isso.