The data types do overflow, your example proves it. What they do not do is throw an exception when overflowing.
In Java an Exception generally must be declared, and in doing so, must be caught. Yes, there are some scenarios where this doesn't hold (Errors, RuntimeExceptions, etc.) but such rules hold fast for the MAJORITY of exceptions.
If you wanted a MathOverflowException, then you would need to catch it. Otherwise it would serve no purpose. That would mean you would need to write code that looked like this
try {
int x = 5 + 7;
} catch (MathOverflowException e) {
// do something
}
Now this is where it gets really nasty. What "throws" the exception? It must be the "plus" sign, right? Well, only sort of. Methods on Objects throw exceptions, so that would mean the plus sign would have to be a "method" on the "object" 5. Except that in this special mathimatcal case, you don't dereference the method on the object; otherwise it would look like:
try {
int x = 5.+ 7; // Note the dot-plus ".+"
} catch (MathOverflowException e) {
// do something
}
But if you started doing this, then you need parenthesis for the operation.
try {
int x = 5.+(7);
} catch (MathOverflowException e) {
// do something
}
And doing so would imply that the assignment "equals sign" is also a method.
try {
int x.=(5.+(7));
} catch (MathOverflowException e) {
// do something
}
but we didn't create a "new" x, so it needs to be:
try {
(new int x()).=(5.+(7));
} catch (MathOverflowException e) {
// do something
}
or possibly
try {
new int x(5).+(7);
} catch (MathOverflowException e) {
// do something
}
Either way, it's a far trip from the simple algebra style, and Java decided to keep the well known algebra / C-ish / Fortran-ish syntax. In doing so, they quickly discovered that either they would need to make hidden "behind the scenes" rules to support math syntax in an object-oriented manner, or they would just need to dispense with the pretence that their math was object-oriented. They chose the latter.