patternjavaMinor
Practicing arrays with String class methods
Viewed 0 times
arrayswithpracticingmethodsclassstring
Problem
I am a Spanish programming teacher in a vocational training course and we are studying arrays. In order to practice and to get the students familiarized with some methods of the
This is the solution that I will provide to my students. The lack of comments is because the solution will be explained in class.
```
package es.programacion1k.arrays;
import java.util.Arrays;
//Using char arrays from strings with the String.toCharArray () function implement the following methods
//length
//indexOf
//charAt(index)
//lastIndexOf(ch);
//replace(oldChar, newChar)
//substring(beginIndex, endIndex)
//substring(beginIndex)
//equals(anObject)
//trim();
//concat(str)
//endsWith(suffix)
//contains(s)
//indexOf(str)
//split("-");
public class MyStringMethods {
public static void main(String[] args) {
String empty = "";
String ordinary = "Ordinary Test String";
System.out.printf("String Class Method - String: \"%s\" Length: %d%n", empty, empty.length());
System.out.printf("String Class Method - String: \"%s\" Length: %d%n", ordinary, ordinary.length());
System.out.printf("myMethod - String: \"%s\" Length: %d%n", empty, myLength(empty));
System.out.printf("myMethod - String: \"%s\" Length: %d%n", ordinary, myLength(ordinary));
char characterToFind = 'N';
String template = "indexOf - String: \"%s\" character: %c position: %d%n";
String myTemplate = "myIndexOf - String: \"%s\" character: %c position: %d%n";
System.out.printf(template, empty, characterToFind, empty.indexOf(characterToFind));
System.out.printf(myTemplate, empty, characterToFind, myIndexOf(empty, characterToFind));
System.out.printf(template, ordinary, characterToFind, ordinary.indexOf(characterToFind));
System.out.printf(myTemplate, ordinary, characterToFind, myIndexOf(ordinary, characterToFind));
int position = 14
String class, I proposed them to reinvent the wheel, implementing some methods of the String class using char arrays.This is the solution that I will provide to my students. The lack of comments is because the solution will be explained in class.
```
package es.programacion1k.arrays;
import java.util.Arrays;
//Using char arrays from strings with the String.toCharArray () function implement the following methods
//length
//indexOf
//charAt(index)
//lastIndexOf(ch);
//replace(oldChar, newChar)
//substring(beginIndex, endIndex)
//substring(beginIndex)
//equals(anObject)
//trim();
//concat(str)
//endsWith(suffix)
//contains(s)
//indexOf(str)
//split("-");
public class MyStringMethods {
public static void main(String[] args) {
String empty = "";
String ordinary = "Ordinary Test String";
System.out.printf("String Class Method - String: \"%s\" Length: %d%n", empty, empty.length());
System.out.printf("String Class Method - String: \"%s\" Length: %d%n", ordinary, ordinary.length());
System.out.printf("myMethod - String: \"%s\" Length: %d%n", empty, myLength(empty));
System.out.printf("myMethod - String: \"%s\" Length: %d%n", ordinary, myLength(ordinary));
char characterToFind = 'N';
String template = "indexOf - String: \"%s\" character: %c position: %d%n";
String myTemplate = "myIndexOf - String: \"%s\" character: %c position: %d%n";
System.out.printf(template, empty, characterToFind, empty.indexOf(characterToFind));
System.out.printf(myTemplate, empty, characterToFind, myIndexOf(empty, characterToFind));
System.out.printf(template, ordinary, characterToFind, ordinary.indexOf(characterToFind));
System.out.printf(myTemplate, ordinary, characterToFind, myIndexOf(ordinary, characterToFind));
int position = 14
Solution
Object-oriented
The first comment, is that all of the methods are
Consider having the starting template of:
Then the rest of the code can operate on the character array alone, without interference from a
Unit testing
Right now, all of the test code is written inside the
A simple JUnit test would be
The methods
The currently all follow the pattern of fetching the character array from the given String parameter. When refactoring this to the
you can directly have
Keep in mind that the methods differ slightly from the ones of the
Be careful with the implementation of
This is because the rewritten
A note regarding
The method
The rest of the code is fine; just make sure to remove the unused variable (
The first comment, is that all of the methods are
static, and their names begin with my.... Java is an object-oriented language, so in order to re-implement a String class working on character arrays, it would be preferable to create a new MyString class. On that class, you can then have the typical methods length() or trim(), with a clear name (instead of having them prefixed with my).Consider having the starting template of:
public class MyString {
private char[] characters;
public MyString(String str) {
characters = str.toCharArray();
}
public int length() {
// ...
}
}Then the rest of the code can operate on the character array alone, without interference from a
String parameter to a static method. The big advantage with this approach is that you gainUnit testing
Right now, all of the test code is written inside the
main method. While this can work during development to easily test some scenarios, having a proper unit test, written with JUnit or TestNG for example, is preferable: you can create this test class on your side, and verify automatically the all of the students submissions with it.A simple JUnit test would be
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class MyStringTest {
@Test
public int testLengthOfEmptyString() {
MyString str = new MyString("");
assertEquals(0, str.length());
}
// more tests (one with a non empty string for example)
}The methods
The currently all follow the pattern of fetching the character array from the given String parameter. When refactoring this to the
MyString class having a character array field, this is simplified. Instead of static int myLength(String s) {
char[] characters = s.toCharArray();
return characters.length;
}you can directly have
public int length() {
return characters.length;
}Keep in mind that the methods differ slightly from the ones of the
String class (charAt method returns a char instead of an int, or indexOf takes an int as parameter instead of a char, etc.), although it may not matter since the point is to learn arrays. I also noticed that some of them are private (like mySubstring); was that the intent? They should probably be made public and to be implemented by the student.Be careful with the implementation of
trim(), it does not have the same behaviour as String.trim(). For example, consider the following String having a paragraph separator (e.g. \u2029), and a tabulation character (to see the difference):System.out.println("\u2029\tABAB".trim()); // prints " ABAB"
System.out.println(myTrim("\u2029\tABAB")); // prints "ABAB"This is because the rewritten
trim() removes all Java white space characters as returned by isWhitespace, but the trim() built-in considers all characters below ' '.A note regarding
split as well: currently it fails if it is passed an empty String. That case should be taken care of: it could be by returning an array of all the characters, like the built-in split does, but the intent for this method is more to accept a char separator as parameter, instead of a String, because what it does is split by a single character.The method
split can be implemented in a more direct way, still reasoning on the character arrays: step 1 is to calculate the total number of tokens and step 2 is to loop over the characters, keeping the running index where a character equal to the separator is found (starting at 0) and taking the substring between that index and the next one (I used Arrays.copyOfRange in the snippet below, but that can easily be replaced with a for loop if you wish to keep it strictly without utility methods).public String[] split(char separator) {
int length = characters.length;
int tokens = 0;
for (char ch : characters) {
if (ch == separator) {
tokens++;
}
}
String[] result = new String[tokens + 1];
int resultIndex = 0;
int startIndex = 0;
for (int i = 0; i < length; i++) {
if (characters[i] == separator) {
result[resultIndex] = new String(Arrays.copyOfRange(characters, startIndex, i));
startIndex = i + 1; // + 1 to skip the separator
resultIndex++;
}
}
// to take the last part into account
result[resultIndex] = new String(Arrays.copyOfRange(characters, startIndex, length));
return result;
}The rest of the code is fine; just make sure to remove the unused variable (
int iguales = 0;) and commented-out code in indexOf(toFind).Code Snippets
public class MyString {
private char[] characters;
public MyString(String str) {
characters = str.toCharArray();
}
public int length() {
// ...
}
}import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class MyStringTest {
@Test
public int testLengthOfEmptyString() {
MyString str = new MyString("");
assertEquals(0, str.length());
}
// more tests (one with a non empty string for example)
}static int myLength(String s) {
char[] characters = s.toCharArray();
return characters.length;
}public int length() {
return characters.length;
}System.out.println("\u2029\tABAB".trim()); // prints " ABAB"
System.out.println(myTrim("\u2029\tABAB")); // prints "ABAB"Context
StackExchange Code Review Q#152326, answer score: 2
Revisions (0)
No revisions yet.