Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Java Sucks (So C# Didn't Have To)

Java Sucks (So C# Didn't Have To)

Avatar for Adele Carpenter

Adele Carpenter

September 04, 2025
Tweet

More Decks by Adele Carpenter

Other Decks in Technology

Transcript

  1. It is NOT about hating Java • An honest look

    at some frustrating aspects of Java • Context to decisions made with respect to design philosophy • Compare choices with C# What is this talk about? https://www.reddit.com/r/ProgrammerHumor/comments/ddc4b0/microso ft _java/
  2. // Java public class Main { public static void main(String[]

    args) { System.out.println("Hello, world!"); } } # Python print("Hello, world!")
  3. // C++ #include <iostream> int main() { std::cout << "Hello,

    world!" << std::endl; return 0; } // Java public class Main { public static void main(String[] args) { System.out.println("Hello, world!"); } }
  4. Smalltalk Earliest and purest OOP language Mesa Structured exception handling,

    concurrency, portable byte code Cedar GC, modularity, type safety and integrated development environment! https://xeroxnostalgia.com/2020/05/24/parc-celebrates-50-years/
  5. 2. Robust and Secure • Automatic garbage collection • Borrowed

    from Cedar and SmallTalk • Java innovations: stop the world collection, heap segmentation, safe points and write barriers • All picked up by C# • Strong compile-time and runtime checking • Borrowed from Cedar and Mesa • Sandbox model • Bytecode veri fi er
  6. 3. Architecture-Neutral and Portable • Java Bytecode • Java Virtual

    Machine (JVM) Speci fi cation • Each OS has own implementation • Similar approach adopted by C# • Microso ft Intermediate Language and Common Language Runtime (CLR)
  7. 4. Highly Performant • Bytecode instruction set compact and e

    ffi cient for interpretation • Just in Time (JIT) compiler • JIT compiler converts bytecode into native machine code at runtime • Not in Java 1.0 • But the design made room for it in future versions • C# 1.0 did ship with JIT compiler • …when it was released 6 years a ft er Java 1.0
  8. 5. Interpreted, Threaded, and Dynamic • Multi-threading that “just worked”

    • Allowed a high degree of interactivity for the end user • Threading model based on Cedar and Mesa
  9. 5. Interpreted, Threaded, and Dynamic • Multi-threading that “just worked”

    • Allowed a high degree of interactivity for the end user • Threading model based on Cedar and Mesa • Classes loaded dynamically at runtime via the ClassLoader • C# uses reflection, assemblies, and optional dynamic typing instead
  10. Java 1.0 Design goals 1. Simple, Object-Oriented, and Familiar 2.

    Robust and Secure 3. Architecture-Neutral and Portable 4. High Performance 5. Interpreted, Threaded, and Dynamic https://www.oracle.com/java/technologies/language-environment.html
  11. public class Box<T> { private T value; public Box(T value)

    { this.value = value; } public void printValue() { println("Value: " + value); } public void printType() { println("Type of T is: " + value.getClass()); } }
  12. public class Box<T> { private T value; public Box(T value)

    { this.value = value; } public void printValue() { Console.WriteLine($"Value: {value}"); } public void printType() { Console.WriteLine($"Type of T is: {typeof(T)}"); } }
  13. public class BoxPrintDemo { public static void run() { var

    intBox = new Box<int>(42); var stringBox = new Box<string>("Hello"); intBox.printType(); stringBox.printType(); intBox.printValue(); stringBox.printValue(); } }
  14. public class Box<T> { private T value; public Box(T value)

    { this.value = value; } public void printValue() { println("Value: " + value); } public void printType() { println("Type of T is: " + value.getClass()); } }
  15. Box<Integer> intBox = new Box<>(42); Box<String> stringBox = new Box<>("Hello");

    println(intBox.getClass() == stringBox.getClass()); // true // Java
  16. Box<?> intBox = new Box<Integer>(42); if (intBox instanceof Box<Integer>) {

    intBox.printValue(); // compile time error!! // java.lang.Object cannot be safely cast to // javasucks.Box<java.lang.Integer> } // Java
  17. “As sort of a design principle for something lots of

    people were going to use, I’d rather keep the hole with a label on it than do something I know is wrong.” James Gosling Faces of Open Source / Peter Adams
  18. Green Team member “We were right about needing to fi

    nish the language even though it had missing features… there was only about a three month window in which the whole Java phenomenon could have happened. We barely made it… [but] Bill was absolutely right about what Java needs long term.”
  19. “As soon as you get a community around something, you

    have to have conversations with people about how to do this, how to do that. If you do the wrong thing, people get very upset. Once upon a time it was just me, and if I wanted to make a major change to the language, it’d take 10 minutes.” James Gosling Faces of Open Source / Peter Adams
  20. “Getting a dozen JVM vendors to agree on if, and

    how, type information would be rei fi ed at runtime was a highly questionable proposition.” Brian Goetz, Java Language Architect at Oracle Photo courtesy of Devoxx Belgium 2023: https://www.flickr.com/photos/bejug/53236104163/in/album-72177720311726414
  21. Type Erasure Was The Choice At the given time, with

    the given amount of java code in the world, and the given importance of backwards compatibility, by the given community, generics with type erasure was the choice
  22. Y’all smug af • CLR allowed pre- and post-generic code

    to run side by side • Had to recompile or manually cast to expected type • Adding generics to the CLR was a decision that only Microso ft had to make What about C#?
  23. List<String> localSchools = List.of("SOME SCHOOL", "THE SCHOOL", "A SCHOOL"); List<String>

    studentIds = List.of("student1", "student2", “student3"); return studentIds.stream() .map(SchoolService::fetchStudentSchoolName) .map(SchoolService::parseSchoolName) .filter(localSchools::contains) .toList() .size();
  24. static String parseSchoolName(String school) throws SchoolParseException { // code goes

    here } static String fetchStudentSchoolName(String studentId) throws IOException { // code goes here }
  25. return studentIds.stream() .map(student -> { try { return fetchStudentSchoolName(student); }

    catch (IOException e) { throw new RuntimeException(e.getMessage()); } }) .map(school -> { try { return parseSchoolName(school); } catch (SchoolParseException e) { throw new RuntimeException(e.getMessage()); } }) .filter(localSchools::contains) .toList() .size();
  26. Faces of Open Source / Peter Adams “In Java you

    can ignore exceptions, but you have to wilfully do it. You can't accidentally say, "I don't care." You have to explicitly say, "I don't care.” James Gosling
  27. “You don't want a program where in 100 di ff

    erent places you handle exceptions and pop up error dialogs… That's just terrible. The exception handling should be centralised, and you should just protect yourself as the exceptions propagate out to the handler.” Anders Hejlsberg Photo: DBegley, CC BY 2.0, via Wikimedia Commons
  28. @FunctionalInterface public interface ThrowingFun<T, R, E extends Exception> { R

    apply(T t) throws E; } static <T, R> Function<T, R> checkedWrapper(ThrowingFun<T, R, Exception> throwingFun) { return t -> { try { return throwingFun.apply(t); } catch (Exception e) { throw new RuntimeException(e.getMessage()); } }; } int localStudentCount(List<String> studentIds, List<String> localSchools) { return studentIds.stream() .map(checkedWrapper(SchoolService::fetchStudentSchoolName)) .map(checkedWrapper(SchoolService::parseSchoolName)) .filter(localSchools::contains) .toList() .size(); }
  29. package checkedexceptions.utils; import java.util.function.Function; public class CheckedWrapper { public static

    <T, R> Function<T, R> checkedWrapper(ThrowingFun<T, R, Exception> throwingFun) { return t -> { try { return throwingFun.apply(t); } catch (Exception e) { throw new RuntimeException(e.getMessage()); } }; } @FunctionalInterface public interface ThrowingFun<T, R, E extends Exception> { R apply(T t) throws E; } }
  30. CreateMap<Customer, CustomerDto>() .ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.FirstName))

    .ForMember(dest => dest.LastName, opt => opt.MapFrom(src => src.LastName)) .ForMember(dest => dest.EmailAddress, opt => opt.MapFrom(src => src.EmailAddress)) .ForMember(dest => dest.AddressLine1, opt => opt.MapFrom(src => src.AddressLine1)) .ForMember(dest => dest.AddressLine2, opt => opt.MapFrom(src => src.AddressLine2)) .ForMember(dest => dest.City, opt => opt.MapFrom(src => src.City)) .ForMember(dest => dest.RegionState, opt => opt.MapFrom(src => src.RegionState)) .ForMember(dest => dest.PostalCode, opt => opt.MapFrom(src => src.PostalCode)) .ForMember(dest => dest.Country, opt => opt.MapFrom(src => src.Country)) .ForMember(dest => dest.Location, opt => opt.ResolveUsing( async src => await IpLocatorService.ResolveAsync()) .AfterMap(async (src, dest) => { if (dest.Location == "USA") { dest.TaxRate = await TaxService.FindTax(dest.City, dest.PostalCode); dest.ChargeTaxes = true; } });
  31. And the birth of Java’s type system • Cost of

    memory fetch close to that of arithmetic operations • “Everything is an object” became • “Everything the user can de fi ne is an object” • 8 primitives The 1990s
  32. • Not limited by memory • Performance is hit by

    memory layout and indirection Today Photo: https://local.microso ft .com/nl/blog/frequently-asked-questions-about-our-datacenters/
  33. “We’ve been working on this 10 years which is kind

    of appalling” Brian Goetz at JVM Language Summit 2024 Photo courtesy of Devoxx Belgium 2023: https://www.flickr.com/photos/bejug/53236104163/in/album-72177720311726414
  34. Project Valhalla Deliverables 10 years, *4 JEPs • JEP 401

    (Preview, Java 26?): Value Classes and Objects • Objects that lack identity, and consequentially optimised encodings • JEP 402: Enhanced Primitive Boxing • Allows primitives to be treated more like objects • JEP dra ft : Null-Restricted Value Class Types • Improves the performance of fi elds and arrays with null- restricted value class types • JDK-8303099: Null-Restricted and Nullable Types • Language support for null-aware types and runtime enforcement of null restrictions *plus many more JEPs with preparatory and supporting work
  35. Perhaps, in the same way that legacy flagship so ft

    ware sucks • It’s annoying quirky • It’s evolving - albeit slowly • Healthy and mature ecosystem • It’s a product of decisions past • It’s still everywhere Does Java (Still) Actually Suck?
  36. Resources Demos • https://github.com/adele97/javasucks • https://github.com/adele97/SoCSharpDidntHaveTo Faces of Open Source

    • https://www.facesofopensource.com/james-gosling-2/ • https://www.facesofopensource.com/bill-joy/
  37. Resources 1990s / Early Java • https://www.oracle.com/java/technologies/language-environment.html • https://www.infoworld.com/article/2169448/javaone-conference-report.html •

    https://sdtimes.com/browsers/twenty-years-of-java-through-its-creators-eyes/ • https://www.landley.net/history/mirror/java/javaorigin.html • https://web.archive.org/web/20000816155304/http://java.sun.com/features/ 1999/08/futures.html • http://sunsite.uakom.sk/sunworldonline/swol-06-1996/swol-06-java2.html • https://web.archive.org/web/20010105194400/http://java.sun.com/javaone/ javaone96/Gosling.Baratz.html • https://web.archive.org/web/19961020124245/http://www.sun.com/960416/ javaone.html
  38. Resources Type Erasure • https://openjdk.org/projects/valhalla/design-notes/in-defense-of-erasure • https://pizzacompiler.sourceforge.net/doc/pizza-translation.pdf • https://web.archive.org/web/20010803054958/http://jcp.org/jsr/detail/ 14.jsp

    • https://web.archive.org/web/20000305044304/http://www.sys-con.com/java/ javaone/interviews/gosling.html Checked Exceptions • https://www.reddit.com/r/java/comments/1cct4iq/ if_everyone_hates_checked_exceptions_wheres_the/ • https://www.artima.com/articles/failure-and-exceptions
  39. Resources Project Lambda • https://cr.openjdk.org/~briangoetz/lambda/lambda-state- fi nal.html • https://docs.oracle.com/javase/8/docs/api/java/util/function/package- summary.html

    Project Loom (Virtual Threads) • https://openjdk.org/jeps/444 • https://openjdk.org/jeps/491 • https://netflixtechblog.com/java-21-virtual-threads-dude-wheres-my- lock-3052540e231d
  40. Resources Project Valhalla • https://cr.openjdk.org/~jrose/values/values-0.html • https://openjdk.org/projects/valhalla/design-notes/state-of-valhalla/01-background • https://www.youtube.com/watch?v=IF9l8fYfSnI •

    https://www.infoworld.com/article/2337986/project-valhalla-a-look-inside-javas- epic-refactor.html • https://bugs.openjdk.org/browse/JDK-8303099 • https://openjdk.org/projects/valhalla/ • https://openjdk.org/jeps/401 • https://openjdk.org/jeps/402 • https://openjdk.org/jeps/8316779