What are Java generics and how do they simplify code