简体   繁体   中英

“hashCode” and “toString” should not be called on array instances (SonarLint)

I am passing my code through SonarLint and I came across this linter violation: "hashCode" and "toString" should not be called on array instances .

This is my code:

byte[] lblobPic;
lblobPic = r.get(PEOPLE.PPIC);
if (lblobPic != null) {
    String argStr = lblobPic.toString();
    peopleDto.setUrlPic(argStr);
}

SonarLint gives the following code snippet as a hint to improve my code:

public static void main( String[] args )  {
    String argStr = Arrays.toString(args);
    int argHash = Arrays.hashCode(args);    
}

How should I change my code to satisfy the linter and why?

Actual Answer

SonarLint is suggesting to you, that instead of calling toString() on the array instance, you should rather use the Arrays utility's method.

It suggests you to change your code to something along the lines:

byte[] lblobPic;
lblobPic = r.get(ALUNO.PFOTO);
if (lblobPic != null) {
    String argStr = Arrays.toString(lblobPic);
    peopleDto.setUrlPic(argStr);
}

Reason behind Answer

a) Readability for Humans

Consider the following code snippet:

String[] strings = { "foo", "bar", "bla", "boo" };

System.out.println(strings.toString());
// prints: [Ljava.lang.String;@7852e922 

System.out.println(Arrays.toString(strings));
// prints: [foo, bar, bla, boo]

The Linter rule assumes, that a developer actually wants a readable output of an array (considering its elements) and suggests you to use Arrays.toString() method which does this (as outlined in the documentation ).

Similarly, Arrays.hashCode() considers the elements of the given array in hashing (as outlined in the docoumentation ).

b) Determinism
(per @andi-turner's suggestion)

The Arrays utility's methods, take only the elements into account when constructing a string / calculating a hash. You will always end up with the same string/hash, when using an input array consisting of the same strings (or values of another type) in the same sequence. yourArray.toHashcode() or yourArray.toString() does not give you that.

String argStr = lblobPic.toString();

should better be

String argStr = Arrays.toString(lblobPic);

as the original Object.toString would give a cryptic hex address.

However what you want to achieve, storing bytes as String is a no-go in java, as java uses Unicode for String and char (two bytes, UTF-16), always with a conversion (of an assumed text encoding of those bytes).

Sometimes such bytes are Base64 encoded:

byte[] lblobPic = r.get(ALUNO.PFOTO);
if (lblobPic != null) {
    String argStr = Base64.getUrlEncoder().encode(lblobPic);
    peopleDto.setUrlPic(argStr);
}

Better still to provide a byte[] field in the DTO.


Should the further processing be a problem; there exist embedding of images.

How (normal) Base64 can be used for HTML with an embedded image:

    String argStr = Base64.getEncoder().encode(lblobPic);
    String html = "<img src="data:image/jpeg;base64," + argStr + "\" alt=\"\">";

(JPEG assumed here.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM