Last active
September 22, 2020 00:49
-
-
Save tivrfoa/fd1f53d394ad790f245c0b5ec08024ca to your computer and use it in GitHub Desktop.
Attempt to create an immutable list in Java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| IT DOES NOT WORK | |
| there was a bug in the code ... | |
| It was returning to early from isEverythingFinal and so | |
| not checking all fields. | |
| For example, it does not work for String: | |
| Exception in thread "main" java.lang.IllegalArgumentException: java.lang.String.hash is not final. | |
| */ | |
| import java.lang.reflect.Modifier; | |
| import java.util.List; | |
| import java.util.ArrayList; | |
| public class ImmutableList<T> { | |
| private Class<T> type; | |
| private List<T> list; | |
| public static void main(String[] args) throws Exception { | |
| assert runTests() : "Tests Failed"; | |
| // IllegalArgumentException: Not final ... | |
| // ImmutableList<Foo> il = ImmutableList.<Foo>type(Foo.class) | |
| // .ofList(List.of(new Foo())); | |
| final ImmutableList<X> il = ImmutableList.<X>type(X.class) | |
| .ofList(List.of(new X())); | |
| System.out.println(il.get(0).y.z.name); | |
| } | |
| public T get(int index) { | |
| return list.get(index); | |
| } | |
| private ImmutableList() {} | |
| public static <T> ImmutableList<T> type(Class<T> type) { | |
| if (! isEverythingFinal(type)) { | |
| throw new IllegalArgumentException("Not final ..."); | |
| } | |
| ImmutableList<T> immutableList = new ImmutableList<>(); | |
| immutableList.type = type; | |
| return immutableList; | |
| } | |
| public ImmutableList<T> ofList(List<T> list) { | |
| this.list = list; | |
| return this; | |
| } | |
| public static boolean isEverythingFinal(Class clazz) { | |
| var fields = clazz.getDeclaredFields(); | |
| for (var f : fields) { | |
| if (! Modifier.isFinal(f.getModifiers())) { | |
| System.err.println(clazz.getName() + "." + | |
| f.getName() + " is not final."); | |
| return false; | |
| } | |
| if (! isEverythingFinal(f.getType())) return false; | |
| } | |
| return true; | |
| } | |
| public static boolean runTests() { | |
| System.out.println("======== Is Foo Final? ======="); | |
| boolean test = isEverythingFinal(Foo.class); | |
| System.out.println(test); | |
| assert ! test : "Foo should not be final"; | |
| System.out.println("======== Is Gama Final? ======="); | |
| test = isEverythingFinal(Gama.class); | |
| System.out.println(test); | |
| assert ! test : "Gama should not be final"; | |
| System.out.println("======== Is Baa Final? ======="); | |
| test = isEverythingFinal(Baa.class); | |
| System.out.println(test); | |
| assert test : "Baa shoud be final"; | |
| System.out.println("======== Is X Final? ======="); | |
| test = isEverythingFinal(X.class); | |
| System.out.println(test); | |
| assert test : "X shoud be final"; | |
| return true; | |
| } | |
| } | |
| class Foo { | |
| int a; | |
| } | |
| class Baa { | |
| final int a = 1; | |
| } | |
| class Gama { | |
| final Foo foo = new Foo(); | |
| } | |
| class X { | |
| final Y y = new Y(); | |
| } | |
| class Y { | |
| final String name = "Y"; | |
| final Z z = new Z(); | |
| } | |
| class Z { | |
| final int i = 2; | |
| final String name = "Z"; | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Probably using a constructor is better, then I can make the list final ...