Skip to content

Instantly share code, notes, and snippets.

@tivrfoa
Last active September 22, 2020 00:49
Show Gist options
  • Select an option

  • Save tivrfoa/fd1f53d394ad790f245c0b5ec08024ca to your computer and use it in GitHub Desktop.

Select an option

Save tivrfoa/fd1f53d394ad790f245c0b5ec08024ca to your computer and use it in GitHub Desktop.
Attempt to create an immutable list in Java
/*
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";
}
@tivrfoa

tivrfoa commented Sep 18, 2020

Copy link
Copy Markdown
Author

Probably using a constructor is better, then I can make the list final ...

import java.lang.reflect.Modifier;
import java.util.List;
import java.util.ArrayList;

public class ImmutableList<T> {
	
	private final Class<T> type;
	private final List<T> list;
	
	public static void main(String[] args) throws Exception {
		assert runTests() : "Tests Failed";
	
		// IllegalArgumentException: Not final ...
		// ImmutableList<Foo> il = new ImmutableList<>(Foo.class, List.of(new Foo()));
				
		final ImmutableList<X> il = new ImmutableList<>(X.class, List.of(new X()));
		System.out.println(il.get(0).y.z.name);
	}
	
	public T get(int index) {
		return list.get(index);
	}
	
	public ImmutableList(Class<T> type, List<T> list) {
		if (! isEverythingFinal(type)) {
			throw new IllegalArgumentException("Not final ...");
		}
		this.type = type;
		this.list = list;
	}
	
	public static boolean isEverythingFinal(Class clazz) {
		var fields = clazz.getDeclaredFields();

		for (var f : fields) {
			if (! Modifier.isFinal(f.getModifiers())) return false;
			
			return isEverythingFinal(f.getType());
		}
		
		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";
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment