137 lines
4.0 KiB
Plaintext
137 lines
4.0 KiB
Plaintext
This issue indicates that a cast operation will fail and throw a `ClassCastException`.
|
|
To fix it, make sure only references to objects with a compatible type can be cast.
|
|
|
|
== Why is this an issue?
|
|
|
|
A cast operation allows an object to be "converted" from one type to another.
|
|
The compiler raises an error if it can determine that the target type is incompatible with the declared type of the object, otherwise it accepts the cast.
|
|
However, depending on the actual runtime type of the object, a cast operation may fail at runtime.
|
|
When a cast operation fails, a `ClassCastException` is thrown.
|
|
|
|
=== What is the potential impact?
|
|
|
|
This type of exception is usually unexpected.
|
|
It causes the program to crash or puts it into an inconsistent state.
|
|
Therefore, this issue might impact the availability and reliability of your application, or even result in data loss.
|
|
|
|
== How to fix it
|
|
|
|
When an object is cast, the code makes assumptions about the type of the object.
|
|
A `ClassCastException` indicates that this assumption has been broken.
|
|
If the assumption is reasonable, then some prior logic should ensure that only objects of a compatible type can be cast.
|
|
You should try to identify the code responsible for these checks and fix it.
|
|
|
|
=== Code examples
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,java,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
private String hexString(Object o) {
|
|
return Integer.toHexString((Integer) o); // Noncompliant if hexString is called with a String for example
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
One possible solution is to change `hexString` to only accept integers and adapt call sites.
|
|
|
|
[source,java,diff-id=1,diff-type=compliant]
|
|
----
|
|
private String hexString(Integer i) {
|
|
return Integer.toHexString(i);
|
|
}
|
|
----
|
|
|
|
Another one is to return a default value for types that are not `Integer`.
|
|
Here, the `if` statement with the condition relying on `instanceof` prevents references to objects with an incompatible type from making it to the cast operation.
|
|
|
|
[source,java,diff-id=1,diff-type=compliant]
|
|
----
|
|
private String hexString(Object o) {
|
|
if (o instanceof Integer) {
|
|
return Integer.toHexString((Integer) o);
|
|
}
|
|
return "0x0";
|
|
}
|
|
----
|
|
|
|
The solution to adopt depends on which part of the code should be responsible to handle non-Integer types.
|
|
|
|
=== Going the extra mile
|
|
|
|
Casting is considered an anti-pattern in object-oriented programming.
|
|
It is sometimes necessary, but there often is a better alternative.
|
|
Consider:
|
|
|
|
* Polymorphism
|
|
* The visitor design pattern
|
|
* Pattern matching
|
|
|
|
They come with some guarantees from the compiler, making your code more reliable.
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,java,diff-id=2,diff-type=noncompliant]
|
|
----
|
|
int foo(Shape shape) {
|
|
if (shape instanceof Circle) {
|
|
Circle circle = (Circle) shape;
|
|
// Code for objects of type Circle
|
|
} else if (shape instanceof Square) {
|
|
Square square = (Square) shape;
|
|
// Code for objects of type Square
|
|
}
|
|
// Default
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,java,diff-id=2,diff-type=compliant]
|
|
----
|
|
int foo(Shape shape) {
|
|
return shape.fooValue(...); // Code was moved into subclasses
|
|
}
|
|
----
|
|
|
|
or
|
|
|
|
[source,java,diff-id=2,diff-type=compliant]
|
|
----
|
|
int foo(Shape shape) {
|
|
return shape.accept(new FooVisitor()); // Code was moved into FooVisitor
|
|
}
|
|
----
|
|
|
|
or
|
|
|
|
[source,java,diff-id=2,diff-type=compliant]
|
|
----
|
|
// Java 14+ required
|
|
int foo(Shape shape) {
|
|
if (shape instanceof Circle c) {
|
|
// Code for objects of type Circle
|
|
} else if (shape instanceof Square s) {
|
|
// Code for objects of type Square
|
|
}
|
|
}
|
|
----
|
|
|
|
== Resources
|
|
|
|
=== Documentation
|
|
|
|
* https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/ClassCastException.html[ClassCastException]
|
|
|
|
=== Articles & blog posts
|
|
|
|
* https://refactoring.guru/design-patterns/visitor[Refactoring Guru: Visitor]
|
|
* https://openjdk.org/jeps/394[JEP 394: Pattern Matching for `instanceof`]
|
|
|
|
=== Standards
|
|
|
|
* https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.16[JLS: Cast Expressions]
|
|
* https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.20.2[JLS: Type Comparison Operator `instanceof`]
|
|
|