Situation
I am making a graph class that looks like this:
class ImmutableGraph<G> {
Node<G> selectedNode;
private ImmutableGraph(Node<G> initialNode) { selectedNode = initialNode; }
//many more things
}
and I'm currently using a (nested) builder class like so
public static class GraphBuilder<B> {
Node<B> currentNode;
public GraphBuilder(B value){ currentNode = new Node(value); }
public ImmutableGraph<B> build(){
return new ImmutableGraph<B>(currentNode);
}
//many more things
}
which uses the (nested) node class
private static class Node<N> {
private final N value;
Array<Nodes<N>> neighbours;
public Node(N v){ value = v; }
//many more things
}
Problem
I can't find a way to instantiate my ImmutableGraph using my builder because the return type is not correct. Indeed, compilation suggests that GraphBuilder.build() should return a type ImmutableGraph<Node<B>> and not ImmutableGraph<B>
For now the only solution I found is to change the return type to ImmutableGraph<Node<B>> but that's feels dumb since all graphs (except empty ones) are graphs of nodes. The Node type is also confusing since the user never interacts with it.
edit:
corrected the "new" in the factory method of the builder
I think that your build method should return new ImmutableGraph<B>(currentNode);
import java.util.List;
public class ImmutableGraph<G> {
Node<G> selectedNode;
private ImmutableGraph(Node<G> initialNode) {
selectedNode = initialNode;
}
// many more things
public static class GraphBuilder<B> {
Node<B> currentNode;
public GraphBuilder(B value) {
currentNode = new Node<B>(value);
}
public ImmutableGraph<B> build() {
return new ImmutableGraph<B>(currentNode);
}
// many more things
}
private static class Node<N> {
private final N value;
List<Node<N>> neighbours;
public Node(N v) {
value = v;
}
// many more things
}
public static void main(String[] args) {
GraphBuilder<Integer> builder = new GraphBuilder<Integer>(Integer.MAX_VALUE);
ImmutableGraph<Integer> graph = builder.build();
System.out.println(graph.selectedNode.value);
}
}
Related
I'd like to know whether my implementation of QuestionBuilder violates mutability.
public class Question<T extends Serializable> implements Serializable {
private QuestionHolder<T> questionHolder;
private Question(QuestionHolder<T> questionHolder) {
this.questionHolder = questionHolder;
}
public String getId() {
return questionHolder.id;
}
public int getOrder() {
return questionHolder.order;
}
public QuestionType getType() {
return questionHolder.type;
}
public boolean isImmediate() {
return questionHolder.immediate;
}
public boolean isMandatory() {
return questionHolder.mandatory;
}
public List<T> getSelectedValues() {
return questionHolder.selectedValues;
}
public List<T> getPossibleValues() {
return questionHolder.possibleValues;
}
private static final class QuestionHolder<T extends Serializable> {
private String id;
private int order = 0;
private QuestionType type;
private boolean immediate;
private boolean mandatory;
private List<T> selectedValues;
private List<T> possibleValues;
}
public static final class QuestionBuilder<T extends Serializable> implements Builder<Question<T>> {
private QuestionHolder<T> questionHolder;
public QuestionBuilder(String id) {
questionHolder = new QuestionHolder<>();
questionHolder.id = id;
}
public QuestionBuilder withOrder(int order) {
questionHolder.order = order;
return this;
}
public QuestionBuilder withType(QuestionType questionType) {
questionHolder.type = questionType;
return this;
}
public QuestionBuilder withImmediate(boolean immediate) {
questionHolder.immediate = immediate;
return this;
}
public QuestionBuilder withMandatory(boolean mandatory) {
questionHolder.mandatory = mandatory;
return this;
}
public QuestionBuilder withSelectedValues(List<T> selectedValues) {
questionHolder.selectedValues = selectedValues;
return this;
}
public QuestionBuilder withPossibleValues(List<T> possibleValues) {
questionHolder.possibleValues = possibleValues;
return this;
}
public Question<T> build() {
Question<T> question = new Question<>(questionHolder);
questionHolder = null;
return question;
}
}
}
Or what should I adjust in order to resolve mutability issue. Any suggestions?
If you're worried about thread safety, then your code here is not necessarily thread safe.
It is possible that one thread calls build() and returns a Question pointing to a QuestionHolder. Even though build() sets the holder to null, another thread might not see that null, but instead see the old value of the field. If that other thread called any of your setters, it would potentially mutate the Holder that the Question class had already accessed.
In a single threaded application you would be fine.
As far as I can see, you are mutating the QuestionHolder with each builder call.
What I would do is:
1) Make all properties inside QuestionHolder private and don't create any setters at all.
2) Store each property inside the builder instance and create a new instance of QuestionHolder in the build method of the builder.
For example:
public Question<T> build() {
// DO ALL THE VALIDATIONS NEEDED
QuestionHolder holder = new QuestionHolder(id, order, type, inmediate, mandatory, selectedValues, possibleValues);
return new Question<>(questionHolder);
}
With these approach, you will be mutating the Builder, but that's ok for the Builder Pattern. You will obviously need to create a new Builder instance each time you want to create a Question. If you want to use the same Builder over and over again you will probably need to store some kind of structure inside it (a Map identified by Id, for example).
I'm java virgin. I've made really simple code like below.
class TreeData implements Comparable<TreeData> {
private String sixString;
private ArrayList<Integer> stringNum = new ArrayList<Integer>();
private ArrayList<Integer> charNum = new ArrayList<Integer>();
public TreeData(String sixString, int stringNum, int charNum){
this.sixString = sixString;
(this.stringNum).add(stringNum);
(this.charNum).add(charNum);
}
public int compareTo(TreeData other) {
return sixString.compareTo(other.getSixString());
}
public String getSixString(){
return sixString;
}
}
class Child<T extends Comparable<T>>{
public void print(T data){
//error : String a = data.getSixString();
System.out.println("hi");
}
}
public class Test {
public static void main(String[] args) {
Child<TreeData> child = new Child<TreeData>();
TreeData td = new TreeData("sixString", 8, 2);
child.print(td);
}
}
I had a problem in 'print' method in the Child class. When I tried calling the getSixString() method of data(passed as argument), it occurs error. I don't know why I can't using public method in the argument 'data'. Is it related with Generic? Thanks, in advance.
In your Child class, you only define T to be extending Comparable. Yet you expect it to have the method getSixString which Comparable doesn't have. What you probably want it for it to be extending TreeData:
class Child<T extends TreeData>{
public void print(T data){
String a = data.getSixString();
//should work now since T defines getSixString()
}
}
Or better yet if all you want is for T to be TreeData, you don't need any generic class. I'm assuming your real intention was:
class Child extends TreeData {
public void print(){
String a = getSixString();
}
}
I have a problem with the generic use I suppose,
Some code:
public class ObservableValue<T> extends Observable {
private T value;
public ObservableValue(T initial) {
setValue(initial);
}
public void setValue(T newValue) {
if (value != newValue) {
this.value = newValue;
setChanged();
notifyObservers(value);
}
}
}
public class SokobanGame implements Game, Observer {
protected final ArrayList<GameStatusBarElement<Integer>> windowElements;
public void nextLevel(Integer currentLevel){
this.windowElements.get(0).getElement().setValue(currentLevel);
for(GameStatusBarElement<Integer> element : windowElements)
element.update();
}
}
public class GameStatusBarElement<T> {
protected final ObservableValue<T> element;
public GameStatusBarElement(String elementText,
ObservableValue<T> observableValue) {
this.element = observableValue;
}
}
And that in the main implementation :
GameStatusBarElement<Integer> level = new GameStatusBarElement<Integer>("Level:", new ObservableValue<Integer>(1));
GameWindow gameWindow = new GameWindow("",
null, null, level);
}
So, the problem is: I cannot use setValue(currentLevel) (in SokobanGame) because of the currentLevel type, eclipse tell me to put something with the T type... But I instantiate the class of this.windowElements.get(0).getElement() with new GameStatusBarElement<Integer>("Level:", new ObservableValue<Integer>(1));, so I don't understand what's the problem ?
Everything seems fine, but I don't see the implementation of your getElement() method.
If your getElement() method is like this one:
public ObservableValue<T> getElement() {
return element;
}
it should compile just fine.
I am currently trying to learn how to use Generics from a book. In this chapter it says to take a piece of data T and convert it to an integer. I am trying different things in Eclipse, but none of them seem to allow this. How could you perform the following task:
LinkedList<T> arr = new LinkedList<T>();
Float fl = 8.74273123948;
arr.add(fl);
Then in another class:
public int findValue(Node node)
{
T data = node.data;
int value = Number.valueOf(data);
return value;
}
I have tried using .valueOf() and (int) among a few other things and nothing seems to satiate Java. The book insists on keeping the method generic in case floats or doubles were used instead of strings or ints.
EDIT: For other people that might have a similar question. Gleaned from all the comments to this question and the answer that was accepted:
use the .toString() on the data and then parse it as you need to whichever data type you need.
Hmm, that is an odd book. I'll try to tell you the gist of it based on what I know.
Generics are a construct that allow you compile-time check of whether a type you are trying to use in a specific collection, method, or class is actually something that knows the functionality that is necessary for that specific thing to function.
For example, you need to use the function determined by the interface called SearchParameter in your template, but you only see the <T> parameter as an object. Or maybe a better example in your case would be a custom interface called IntegerConvert like so:
public interface IntegerConvert
{
Integer returnAsInteger();
}
And you could have a class like this:
public class MyData implements IntegerConvert
{
private String data;
public MyData(String data)
{
this.data = data;
}
#Override
public Integer returnAsInteger()
{
return Integer.parseInt(data); //throws ParseException if it doesn't work
}
}
And then you could have a List of these like this:
List<IntegerConvert> listOfConvertibles = new ArrayList<IntegerConvert>();
or if you want to go a bit more generic for the future,
List<? extends IntegerConvert> listOfConvertibles = new ArrayList<IntegerConvert>();
and then you can do
listOfConvertibles.add("25");
listOfConvertibles.add("40");
listOfConvertibles.add("35");
for(IntegerConvert ic : listOfConvertibles)
{
System.out.println("" + ic.returnAsInteger());
}
Although that was a bit of an overcomplicated example, I guess. A simpler example would be the following:
public class Node<E>
{
private E data;
public Node(E e)
{
this.data = e;
}
public E getData()
{
return data;
}
public void setData(E e)
{
data = e;
}
public void print()
{
System.out.println(data.toString());
}
}
public class MyClass
{
public void doSomething()
{
List<Node<Float>> listOfFloatNodes = new ArrayList<Node<Float>>();
listOfFloatNodes.add(new Node<Float>(new Float(8.7472742f)));
listOfFloatNodes.add(new Node<Float>(new Float(5.56842742f)));
listOfFloatNodes.add(new Node<Float>(new Float(6.5467742f)));
MyOtherClass moc = new MyOtherClass();
moc.useNodeList(listOfFloatNodes);
}
}
public class MyOtherClass
{
public <E> void useNodeList(List<Node<E>> list)
{
for(Node<E> node : list)
{
printNode(node);
}
}
public <E> void printNode(Node<E> node)
{
node.print();
}
}
public class MainClass
{
public static void main(String[] args)
{
MyClass myClass = new MyClass();
myClass.doSomething();
}
}
If you have any questions, comment.
try to observe below examples:
public static void main(String[] args) {
test0("13");
test0(new Integer(13));
test1();
System.out.println(findValue(new Node("10")));
}
private static <T> void test0(T a) {
LinkedList<T> arr = new LinkedList<T>();
arr.add((T) a);
System.out.println(arr.getFirst());
}
private static <T> void test1() {
LinkedList<T> arr = new LinkedList<T>();
arr.add((T) new Integer(13));
System.out.println(arr.getFirst());
}
public static <T> int findValue(Node node) {
T data = (T) node.data;
int value = Integer.valueOf(data.toString());
return value;
}
where Node is :
public class Node {
//this should be private
public String data;
public Node(String data) {
this.data = data;
}
//use getter below to access private data
public String getData() {
return data;
}
}
all this is possible because, unchecked casts from a known type to T is allowed (of course with warnings) and compiler believes you for the casting.
Answer not entirely on the topic albeit closely related. I had a problem and didn't find the answer. Then I found solution and thought I'd share:
I was trying to cast generic value to primitive type:
<TYPE> boolean equal(TYPE val, Class<?> type) {
if (float.class == type) {
float val2 = (float) val; // incompatible types: TYPE cannot be converted to float
float val3 = (float) (Object) val; // works
...
Long story short: first version doesn't work and the second does. Quite annoying.
I have a Node<T> (inner) class in Graph<T> class:
public class Graph<T> {
private ArrayList<Node<T>> vertices;
public boolean addVertex(Node<T> n) {
this.vertices.add(n);
return true;
}
private class Node<T> {...}
}
When I run this:
Graph<Integer> g = new Graph<Integer>();
Node<Integer> n0 = new Node<>(0);
g.addVertex(n0);
The last line give me error:
The method addVertice(Graph<Integer>.Node<Integer>) in the type Graph<Integer> is not applicable for the arguments (Graph<T>.Node<Integer>)
Why? Thanks in advance?
Your inner class should not override T Since T is already used in outerclass. Consider what can happen if it was allowed. Your outer class would have referred to Integer and Inner class would have referred to another class that too for the same instance.
public boolean addEdge(Node node1, Node node2) {
return false;
}
Graph<Integer> g = new Graph<Integer>();
Graph<Integer>.Node n0 = g.new Node(0);// As T happens to be integer you can use inside node class also.
public class Node {
T t;
Node(T t) {
}
}
Or you can use Static Inner class since Static Generics Types are different than instance generic types.
For More Explanation you can Refer to JLS # 4.8. Raw Types
Following code works fine for me. Running on JRE 1.6
public class Generic<T> {
private ArrayList<Node<T>> vertices = new ArrayList<Node<T>>();
public boolean addVertice(Node<T> n) {
this.vertices.add(n);
System.out.println("added");
return true;
}
public static class Node<T> {
}
public static void main(String[] args) {
Generic<Integer> g = new Generic<Integer>();
Node<Integer> n0 = new Node<Integer>();
g.addVertice(n0);
}
}