Printing an Array in Ruby vs. Java
Overview
So recently, I did a redo on an old Turing Mod 1 project called FlashCards but rather than use Ruby, I built it from scratch using Java.
Something I noticed is that it is not so easy to print an array in Java like it is in Ruby. One of the requirements of this project, you are tasked to create a Round class. One of the instance variables you create is called turns
with the default value of an empty array. The turns
instance variable contains every instance of the Turn class along with an instance of the Card class tied to it as well as a guess
in the form of a string.
Before proceeding further, I want to clarify that for Java, I am printing an ArrayList not an Array. For more clarification on the differences between the two, here is a great resource for a more in-depth explanation.
For some context, this is a portion of the Turn class in Ruby containing the initializer.
class Turn
attr_reader :guess, :card
def initialize(guess, card)
@guess = guess
@card = card
end
And this is a portion of the Turn class in Java, showing its constructor and a couple of getters.
public class Turn {
private String guess;
private Card card;
Turn(String guess, Card card) {
this.guess = guess;
this.card = card;
}
public String getGuess() {
return this.guess;
}
public Card getCard() {
return this.card;
}
In Ruby
Let’s focus on the Ruby part first.
This is currently how the Round
class looks like.
class Round
attr_reader :deck, :turns
def initialize(deck)
@deck = deck
@turns = []
end
Lets assume that an instance of a Turn exists in the @turns
array.
According to the iteration, if we simply did this
p round.turns
It will return this.
[#<Turn:0x000000013a965150 @guess="tessa", @card=#<Card:0x000000013a965a88 @question="What is the first name of the main character in Silent Hill 3?", @answer="heather", @category="Video Games">>]
So much like how it is shown in the iteration, it will return the Turn hexadecimal, along with it’s guess and the card tied to it (mainly the hexadecimal), as well as the card’s details (that being a card’s question, answer, and category).
This is what we want to do in Ruby. But what about Java?
In Java
Much like earlier in this post and for some context, here is a portion of the Round class in Java.
import java.util.ArrayList;
import java.util.stream.*;
import java.util.List;
public class Round {
private Deck deck;
private ArrayList<Turn> turnsTaken = new ArrayList<Turn>();
Round(Deck deck) {
this.deck = deck;
}
So if we did this
System.out.println(round.turnsTaken);
This would not work because the .turnsTaken
instance variable is private and we cannot call it this way. However, we can create a method that will return our ArrayList.
I’ll create a getTurns()
method and this is how it looks like
public ArrayList<Turn> getTurns() {
return turnsTaken;
}
Now that we created this method, we will call it.
System.out.println(round.getTurns());
Assuming the ArrayList contains one instance of a Turn, this is the result
[Turn@4aa298b7]
What’s going on here? It’s not printing everything out. It seems to print out the hexadecimal but no other details about the turn. Not the Card details that are tied to the turn nor the turn’s guess.
Hmmmm….how are we able to do this?
It looks like we are going to need something more.
A solution in Java
Part 1: Creating a new ArrayList
So our first attempt wasn’t successful. But when there’s a will, there’s a way.
I’ll be creating a new method called getTurnsTaken()
public String getTurnsTaken() {
}
This method will return a String instead of an ArrayList. Lets add some stuff to it.
First we will create a new ArrayList within the method. We will name it formattedTurnsTaken
. More on that later.
public String getTurnsTaken() {
ArrayList<String> formattedTurnsTaken = new ArrayList<String>();
}
Part 2: forEach()
Next, we will be calling the forEach
method and use it on our instance variable turnsTaken
public String getTurnsTaken() {
ArrayList<String> formattedTurnsTaken = new ArrayList<String>();
turnsTaken.forEach(turn -> {
...
So what’s going on here? We will be iterating through the turnsTaken
ArrayList and we will add
to our newly created formattedTurnsTaken
ArrayList.
Part 3: String.format()
As we iterate through out turnsTaken
ArrayList, we will have access to all instances of Turn, along with the guess and the Turn’s card. Let’s set this up.
public String getTurnsTaken() {
ArrayList<String> formattedTurnsTaken = new ArrayList<String>();
turnsTaken.forEach(turn -> {
formattedTurnsTaken.add(String.format())
...
Now we’re passing through the String format
method. What does this do? We create a new string and format it to our liking. Lets try it.
public String getTurnsTaken() {
ArrayList<String> formattedTurnsTaken = new ArrayList<String>();
turnsTaken.forEach(turn -> {
formattedTurnsTaken.add(String.format("%s card=%s question=%s"))
...
What is %s
? It is a format specifier that will allow us to pass data into the string. The String format
method will allow us to pass in multiple arguments that will add to our string.
Remember, we’re still in the loop and have access to each instance of Turn, the Turn’s card and guess. Let’s add more.
public String getTurnsTaken() {
ArrayList<String> formattedTurnsTaken = new ArrayList<String>();
turnsTaken.forEach(turn -> {
formattedTurnsTaken.add(String.format("%s card=%s question=%s", turn.toString(), turn.getCard(), turn.getCard().getQuestion()))
...
So what did we pass into our method? We passed the Turn hexadecimal, the card hexadecimal, and the card’s question. But this is only part of what it should return.
Let’s complete it like this
public String getTurnsTaken() {
ArrayList<String> formattedTurnsTaken = new ArrayList<String>();
turnsTaken.forEach(turn -> {
formattedTurnsTaken.add(String.format("%s guess=%s card=%s question=%s, answer=%s, category=%s",
turn.toString(), turn.getGuess(), turn.getCard(), turn.getCard().getQuestion(), turn.getCard().getAnswer(), turn.getCard().getCategory()));
});
return formattedTurnsTaken;
}
Now this looks more complete! We have included everything mentioned above as well as the card’s answer and the card’s category.
So this means we’re done right?
Well if we were to run it as it is, it throws an error
System.out.println(round.getTurnsTaken());
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Type mismatch: cannot convert from ArrayList<String> to String
...
What does this mean? Our getTurnsTaken()
method must return a String but instead tries to returns the ArrayList formattedTurnsTaken
. But since we explicitly stated we want to return a string, this will break.
Part 4: toString()
What do we do now? Let’s convert the ArrayList to a String. It’s a simple fix.
All we need to do is add .toString()
to the end of the formattedTurnsTaken
ArrayList.
public String getTurnsTaken() {
ArrayList<String> formattedTurnsTaken = new ArrayList<String>();
turnsTaken.forEach(turn -> {
formattedTurnsTaken.add(String.format("%s card=%s question=%s, answer=%s, category=%s",
turn.toString(), turn.getCard(), turn.getCard().getQuestion(), turn.getCard().getAnswer(), turn.getCard().getCategory()));
});
return formattedTurnsTaken.toString();
}
This will convert formattedTurnsTaken
to a String and now this method will work correctly.
Again, let’s assume there exists an instance of a turn. So now when we print this out
System.out.println(round.getTurnsTaken());
This is what we get.
[Turn@28d93b30 guess=tessa, card=Card@4554617c, question=What is the first name of the main character in Silent Hill 3?, answer=heather, category=Video Games]
We printed the details successfully!
Closing thoughts
Phew! This seems like a lot for Java. But I think this process has allowed me to really challenge myself as someone relearning Java and also appreciate the convenience that Ruby provides.
To anyone looking to start coding in Java, it may seem intimidating but I assure you that it is a very great language to learn. It’s the most fun I had in a while and I’m sure you will enjoy it too!