I have a project in which we often use Integer.parseInt() to convert a String to an int. When something goes wrong (for example, the String is not a number but the letter a, or whatever) this method will throw an exception. However, if I have to handle exceptions in my code everywhere, this starts to look very ugly very quickly. I would like to put this in a method, however, I have no clue how to return a clean value in order to show that the conversion went wrong.
In C++ I could have created a method that accepted a pointer to an int and let the method itself return true or false. However, as far as I know, this is not possible in Java. I could also create an object that contains a true/false variable and the converted value, but this does not seem ideal either. The same thing goes for a global value, and this might give me some trouble with multithreading.
So is there a clean way to do this?
You could return an Integer instead of an int, returning null on parse failure.
It's a shame Java doesn't provide a way of doing this without there being an exception thrown internally though - you can hide the exception (by catching it and returning null), but it could still be a performance issue if you're parsing hundreds of thousands of bits of user-provided data.
EDIT: Code for such a method:
public static Integer tryParse(String text) {
try {
return Integer.parseInt(text);
} catch (NumberFormatException e) {
return null;
}
}
Note that I'm not sure off the top of my head what this will do if text is null. You should consider that - if it represents a bug (i.e. your code may well pass an invalid value, but should never pass null) then throwing an exception is appropriate; if it doesn't represent a bug then you should probably just return null as you would for any other invalid value.
Originally this answer used the new Integer(String) constructor; it now uses Integer.parseInt and a boxing operation; in this way small values will end up being boxed to cached Integer objects, making it more efficient in those situations.
What behaviour do you expect when it's not a number?
If, for example, you often have a default value to use when the input is not a number, then a method such as this could be useful:
public static int parseWithDefault(String number, int defaultVal) {
try {
return Integer.parseInt(number);
} catch (NumberFormatException e) {
return defaultVal;
}
}
Similar methods can be written for different default behaviour when the input can't be parsed.
In some cases you should handle parsing errors as fail-fast situations, but in others cases, such as application configuration, I prefer to handle missing input with default values using Apache Commons Lang 3 NumberUtils.
int port = NumberUtils.toInt(properties.getProperty("port"), 8080);
To avoid handling exceptions use a regular expression to make sure you have all digits first:
//Checking for Regular expression that matches digits
if(value.matches("\\d+")) {
Integer.parseInt(value);
}
There is Ints.tryParse() in Guava. It doesn't throw exception on non-numeric string, however it does throw exception on null string.
After reading the answers to the question I think encapsulating or wrapping the parseInt method is not necessary, maybe even not a good idea.
You could return 'null' as Jon suggested, but that's more or less replacing a try/catch construct by a null-check. There's just a slight difference on the behaviour if you 'forget' error handling: if you don't catch the exception, there's no assignment and the left hand side variable keeps it old value. If you don't test for null, you'll probably get hit by the JVM (NPE).
yawn's suggestion looks more elegant to me, because I do not like returning null to signal some errors or exceptional states. Now you have to check referential equality with a predefined object, that indicates a problem. But, as others argue, if again you 'forget' to check and a String is unparsable, the program continous with the wrapped int inside your 'ERROR' or 'NULL' object.
Nikolay's solution is even more object orientated and will work with parseXXX methods from other wrapper classes aswell. But in the end, he just replaced the NumberFormatException by an OperationNotSupported exception - again you need a try/catch to handle unparsable inputs.
So, its my conclusion to not encapsulate the plain parseInt method. I'd only encapsulate if I could add some (application depended) error handling as well.
May be you can use something like this:
public class Test {
public interface Option<T> {
T get();
T getOrElse(T def);
boolean hasValue();
}
final static class Some<T> implements Option<T> {
private final T value;
public Some(T value) {
this.value = value;
}
#Override
public T get() {
return value;
}
#Override
public T getOrElse(T def) {
return value;
}
#Override
public boolean hasValue() {
return true;
}
}
final static class None<T> implements Option<T> {
#Override
public T get() {
throw new UnsupportedOperationException();
}
#Override
public T getOrElse(T def) {
return def;
}
#Override
public boolean hasValue() {
return false;
}
}
public static Option<Integer> parseInt(String s) {
Option<Integer> result = new None<Integer>();
try {
Integer value = Integer.parseInt(s);
result = new Some<Integer>(value);
} catch (NumberFormatException e) {
}
return result;
}
}
You could also replicate the C++ behaviour that you want very simply
public static boolean parseInt(String str, int[] byRef) {
if(byRef==null) return false;
try {
byRef[0] = Integer.parseInt(prop);
return true;
} catch (NumberFormatException ex) {
return false;
}
}
You would use the method like so:
int[] byRef = new int[1];
boolean result = parseInt("123",byRef);
After that the variable result it's true if everything went allright and byRef[0] contains the parsed value.
Personally, I would stick to catching the exception.
I know that this is quite an old question, but I was looking for a modern solution to solve that issue.
I came up with the following solution:
public static OptionalInt tryParseInt(String string) {
try {
return OptionalInt.of(Integer.parseInt(string));
} catch (NumberFormatException e) {
return OptionalInt.empty();
}
}
Usage:
#Test
public void testTryParseIntPositive() {
// given
int expected = 5;
String value = "" + expected;
// when
OptionalInt optionalInt = tryParseInt(value);
// then
Assert.assertTrue(optionalInt.isPresent());
Assert.assertEquals(expected, optionalInt.getAsInt());
}
#Test
public void testTryParseIntNegative() {
// given
int expected = 5;
String value = "x" + expected;
// when
OptionalInt optionalInt = tryParseInt(value);
// then
Assert.assertTrue(optionalInt.isEmpty());
}
My Java is a little rusty, but let me see if I can point you in the right direction:
public class Converter {
public static Integer parseInt(String str) {
Integer n = null;
try {
n = new Integer(Integer.tryParse(str));
} catch (NumberFormatException ex) {
// leave n null, the string is invalid
}
return n;
}
}
If your return value is null, you have a bad value. Otherwise, you have a valid Integer.
The answer given by Jon Skeet is fine, but I don't like giving back a null Integer object. I find this confusing to use. Since Java 8 there is a better option (in my opinion), using the OptionalInt:
public static OptionalInt tryParse(String value) {
try {
return OptionalInt.of(Integer.parseInt(value));
} catch (NumberFormatException e) {
return OptionalInt.empty();
}
}
This makes it explicit that you have to handle the case where no value is available. I would prefer if this kind of function would be added to the java library in the future, but I don't know if that will ever happen.
What about forking the parseInt method?
It's easy, just copy-paste the contents to a new utility that returns Integer or Optional<Integer> and replace throws with returns. It seems there are no exceptions in the underlying code, but better check.
By skipping the whole exception handling stuff, you can save some time on invalid inputs. And the method is there since JDK 1.0, so it is not likely you will have to do much to keep it up-to-date.
If you're using Java 8 or up, you can use a library I just released: https://github.com/robtimus/try-parse. It has support for int, long and boolean that doesn't rely on catching exceptions. Unlike Guava's Ints.tryParse it returns OptionalInt / OptionalLong / Optional, much like in https://stackoverflow.com/a/38451745/1180351 but more efficient.
Maybe someone is looking for a more generic approach, since Java 8 there is the Package java.util.function that allows to define Supplier Functions. You could have a function that takes a supplier and a default value as follows:
public static <T> T tryGetOrDefault(Supplier<T> supplier, T defaultValue) {
try {
return supplier.get();
} catch (Exception e) {
return defaultValue;
}
}
With this function, you can execute any parsing method or even other methods that could throw an Exception while ensuring that no Exception can ever be thrown:
Integer i = tryGetOrDefault(() -> Integer.parseInt(stringValue), 0);
Long l = tryGetOrDefault(() -> Long.parseLong(stringValue), 0l);
Double d = tryGetOrDefault(() -> Double.parseDouble(stringValue), 0d);
I would suggest you consider a method like
IntegerUtilities.isValidInteger(String s)
which you then implement as you see fit. If you want the result carried back - perhaps because you use Integer.parseInt() anyway - you can use the array trick.
IntegerUtilities.isValidInteger(String s, int[] result)
where you set result[0] to the integer value found in the process.
This is somewhat similar to Nikolay's solution:
private static class Box<T> {
T me;
public Box() {}
public T get() { return me; }
public void set(T fromParse) { me = fromParse; }
}
private interface Parser<T> {
public void setExclusion(String regex);
public boolean isExcluded(String s);
public T parse(String s);
}
public static <T> boolean parser(Box<T> ref, Parser<T> p, String toParse) {
if (!p.isExcluded(toParse)) {
ref.set(p.parse(toParse));
return true;
} else return false;
}
public static void main(String args[]) {
Box<Integer> a = new Box<Integer>();
Parser<Integer> intParser = new Parser<Integer>() {
String myExclusion;
public void setExclusion(String regex) {
myExclusion = regex;
}
public boolean isExcluded(String s) {
return s.matches(myExclusion);
}
public Integer parse(String s) {
return new Integer(s);
}
};
intParser.setExclusion("\\D+");
if (parser(a,intParser,"123")) System.out.println(a.get());
if (!parser(a,intParser,"abc")) System.out.println("didn't parse "+a.get());
}
The main method demos the code. Another way to implement the Parser interface would obviously be to just set "\D+" from construction, and have the methods do nothing.
They way I handle this problem is recursively. For example when reading data from the console:
Java.util.Scanner keyboard = new Java.util.Scanner(System.in);
public int GetMyInt(){
int ret;
System.out.print("Give me an Int: ");
try{
ret = Integer.parseInt(keyboard.NextLine());
}
catch(Exception e){
System.out.println("\nThere was an error try again.\n");
ret = GetMyInt();
}
return ret;
}
To avoid an exception, you can use Java's Format.parseObject method. The code below is basically a simplified version of Apache Common's IntegerValidator class.
public static boolean tryParse(String s, int[] result)
{
NumberFormat format = NumberFormat.getIntegerInstance();
ParsePosition position = new ParsePosition(0);
Object parsedValue = format.parseObject(s, position);
if (position.getErrorIndex() > -1)
{
return false;
}
if (position.getIndex() < s.length())
{
return false;
}
result[0] = ((Long) parsedValue).intValue();
return true;
}
You can either use AtomicInteger or the int[] array trick depending upon your preference.
Here is my test that uses it -
int[] i = new int[1];
Assert.assertTrue(IntUtils.tryParse("123", i));
Assert.assertEquals(123, i[0]);
I was also having the same problem. This is a method I wrote to ask the user for an input and not accept the input unless its an integer. Please note that I am a beginner so if the code is not working as expected, blame my inexperience !
private int numberValue(String value, boolean val) throws IOException {
//prints the value passed by the code implementer
System.out.println(value);
//returns 0 is val is passed as false
Object num = 0;
while (val) {
num = br.readLine();
try {
Integer numVal = Integer.parseInt((String) num);
if (numVal instanceof Integer) {
val = false;
num = numVal;
}
} catch (Exception e) {
System.out.println("Error. Please input a valid number :-");
}
}
return ((Integer) num).intValue();
}
This is an answer to question 8391979, "Does java have a int.tryparse that doesn't throw an exception for bad data? [duplicate]" which is closed and linked to this question.
Edit 2016 08 17: Added ltrimZeroes methods and called them in tryParse(). Without leading zeroes in numberString may give false results (see comments in code). There is now also public static String ltrimZeroes(String numberString) method which works for positive and negative "numbers"(END Edit)
Below you find a rudimentary Wrapper (boxing) class for int with an highly speed optimized tryParse() method (similar as in C#) which parses the string itself and is a little bit faster than Integer.parseInt(String s) from Java:
public class IntBoxSimple {
// IntBoxSimple - Rudimentary class to implement a C#-like tryParse() method for int
// A full blown IntBox class implementation can be found in my Github project
// Copyright (c) 2016, Peter Sulzer, Fürth
// Program is published under the GNU General Public License (GPL) Version 1 or newer
protected int _n; // this "boxes" the int value
// BEGIN The following statements are only executed at the
// first instantiation of an IntBox (i. e. only once) or
// already compiled into the code at compile time:
public static final int MAX_INT_LEN =
String.valueOf(Integer.MAX_VALUE).length();
public static final int MIN_INT_LEN =
String.valueOf(Integer.MIN_VALUE).length();
public static final int MAX_INT_LASTDEC =
Integer.parseInt(String.valueOf(Integer.MAX_VALUE).substring(1));
public static final int MAX_INT_FIRSTDIGIT =
Integer.parseInt(String.valueOf(Integer.MAX_VALUE).substring(0, 1));
public static final int MIN_INT_LASTDEC =
-Integer.parseInt(String.valueOf(Integer.MIN_VALUE).substring(2));
public static final int MIN_INT_FIRSTDIGIT =
Integer.parseInt(String.valueOf(Integer.MIN_VALUE).substring(1,2));
// END The following statements...
// ltrimZeroes() methods added 2016 08 16 (are required by tryParse() methods)
public static String ltrimZeroes(String s) {
if (s.charAt(0) == '-')
return ltrimZeroesNegative(s);
else
return ltrimZeroesPositive(s);
}
protected static String ltrimZeroesNegative(String s) {
int i=1;
for ( ; s.charAt(i) == '0'; i++);
return ("-"+s.substring(i));
}
protected static String ltrimZeroesPositive(String s) {
int i=0;
for ( ; s.charAt(i) == '0'; i++);
return (s.substring(i));
}
public static boolean tryParse(String s,IntBoxSimple intBox) {
if (intBox == null)
// intBoxSimple=new IntBoxSimple(); // This doesn't work, as
// intBoxSimple itself is passed by value and cannot changed
// for the caller. I. e. "out"-arguments of C# cannot be simulated in Java.
return false; // so we simply return false
s=s.trim(); // leading and trailing whitespace is allowed for String s
int len=s.length();
int rslt=0, d, dfirst=0, i, j;
char c=s.charAt(0);
if (c == '-') {
if (len > MIN_INT_LEN) { // corrected (added) 2016 08 17
s = ltrimZeroesNegative(s);
len = s.length();
}
if (len >= MIN_INT_LEN) {
c = s.charAt(1);
if (!Character.isDigit(c))
return false;
dfirst = c-'0';
if (len > MIN_INT_LEN || dfirst > MIN_INT_FIRSTDIGIT)
return false;
}
for (i = len - 1, j = 1; i >= 2; --i, j *= 10) {
c = s.charAt(i);
if (!Character.isDigit(c))
return false;
rslt -= (c-'0')*j;
}
if (len < MIN_INT_LEN) {
c = s.charAt(i);
if (!Character.isDigit(c))
return false;
rslt -= (c-'0')*j;
} else {
if (dfirst >= MIN_INT_FIRSTDIGIT && rslt < MIN_INT_LASTDEC)
return false;
rslt -= dfirst * j;
}
} else {
if (len > MAX_INT_LEN) { // corrected (added) 2016 08 16
s = ltrimZeroesPositive(s);
len=s.length();
}
if (len >= MAX_INT_LEN) {
c = s.charAt(0);
if (!Character.isDigit(c))
return false;
dfirst = c-'0';
if (len > MAX_INT_LEN || dfirst > MAX_INT_FIRSTDIGIT)
return false;
}
for (i = len - 1, j = 1; i >= 1; --i, j *= 10) {
c = s.charAt(i);
if (!Character.isDigit(c))
return false;
rslt += (c-'0')*j;
}
if (len < MAX_INT_LEN) {
c = s.charAt(i);
if (!Character.isDigit(c))
return false;
rslt += (c-'0')*j;
}
if (dfirst >= MAX_INT_FIRSTDIGIT && rslt > MAX_INT_LASTDEC)
return false;
rslt += dfirst*j;
}
intBox._n=rslt;
return true;
}
// Get the value stored in an IntBoxSimple:
public int get_n() {
return _n;
}
public int v() { // alternative shorter version, v for "value"
return _n;
}
// Make objects of IntBoxSimple (needed as constructors are not public):
public static IntBoxSimple makeIntBoxSimple() {
return new IntBoxSimple();
}
public static IntBoxSimple makeIntBoxSimple(int integerNumber) {
return new IntBoxSimple(integerNumber);
}
// constructors are not public(!=:
protected IntBoxSimple() {} {
_n=0; // default value an IntBoxSimple holds
}
protected IntBoxSimple(int integerNumber) {
_n=integerNumber;
}
}
Test/example program for class IntBoxSimple:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class IntBoxSimpleTest {
public static void main (String args[]) {
IntBoxSimple ibs = IntBoxSimple.makeIntBoxSimple();
String in = null;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
do {
System.out.printf(
"Enter an integer number in the range %d to %d:%n",
Integer.MIN_VALUE, Integer.MAX_VALUE);
try { in = br.readLine(); } catch (IOException ex) {}
} while(! IntBoxSimple.tryParse(in, ibs));
System.out.printf("The number you have entered was: %d%n", ibs.v());
}
}
Try with regular expression and default parameters argument
public static int parseIntWithDefault(String str, int defaultInt) {
return str.matches("-?\\d+") ? Integer.parseInt(str) : defaultInt;
}
int testId = parseIntWithDefault("1001", 0);
System.out.print(testId); // 1001
int testId = parseIntWithDefault("test1001", 0);
System.out.print(testId); // 1001
int testId = parseIntWithDefault("-1001", 0);
System.out.print(testId); // -1001
int testId = parseIntWithDefault("test", 0);
System.out.print(testId); // 0
if you're using apache.commons.lang3 then by using NumberUtils:
int testId = NumberUtils.toInt("test", 0);
System.out.print(testId); // 0
I would like to throw in another proposal that works if one specifically requests integers: Simply use long and use Long.MIN_VALUE for error cases. This is similar to the approach that is used for chars in Reader where Reader.read() returns an integer in the range of a char or -1 if the reader is empty.
For Float and Double, NaN can be used in a similar way.
public static long parseInteger(String s) {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
return Long.MIN_VALUE;
}
}
// ...
long l = parseInteger("ABC");
if (l == Long.MIN_VALUE) {
// ... error
} else {
int i = (int) l;
}
Considering existing answers, I've copy-pasted and enhanced source code of Integer.parseInt to do the job, and my solution
does not use potentially slow try-catch (unlike Lang 3 NumberUtils),
does not use regexps which can't catch too big numbers,
avoids boxing (unlike Guava's Ints.tryParse()),
does not require any allocations (unlike int[], Box, OptionalInt),
accepts any CharSequence or a part of it instead of a whole String,
can use any radix which Integer.parseInt can, i.e. [2,36],
does not depend on any libraries.
The only downside is that there's no difference between toIntOfDefault("-1", -1) and toIntOrDefault("oops", -1).
public static int toIntOrDefault(CharSequence s, int def) {
return toIntOrDefault0(s, 0, s.length(), 10, def);
}
public static int toIntOrDefault(CharSequence s, int def, int radix) {
radixCheck(radix);
return toIntOrDefault0(s, 0, s.length(), radix, def);
}
public static int toIntOrDefault(CharSequence s, int start, int endExclusive, int def) {
boundsCheck(start, endExclusive, s.length());
return toIntOrDefault0(s, start, endExclusive, 10, def);
}
public static int toIntOrDefault(CharSequence s, int start, int endExclusive, int radix, int def) {
radixCheck(radix);
boundsCheck(start, endExclusive, s.length());
return toIntOrDefault0(s, start, endExclusive, radix, def);
}
private static int toIntOrDefault0(CharSequence s, int start, int endExclusive, int radix, int def) {
if (start == endExclusive) return def; // empty
boolean negative = false;
int limit = -Integer.MAX_VALUE;
char firstChar = s.charAt(start);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+') {
return def;
}
start++;
// Cannot have lone "+" or "-"
if (start == endExclusive) return def;
}
int multmin = limit / radix;
int result = 0;
while (start < endExclusive) {
// Accumulating negatively avoids surprises near MAX_VALUE
int digit = Character.digit(s.charAt(start++), radix);
if (digit < 0 || result < multmin) return def;
result *= radix;
if (result < limit + digit) return def;
result -= digit;
}
return negative ? result : -result;
}
private static void radixCheck(int radix) {
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
throw new NumberFormatException(
"radix=" + radix + " ∉ [" + Character.MIN_RADIX + "," + Character.MAX_RADIX + "]");
}
private static void boundsCheck(int start, int endExclusive, int len) {
if (start < 0 || start > len || start > endExclusive)
throw new IndexOutOfBoundsException("start=" + start + " ∉ [0, min(" + len + ", " + endExclusive + ")]");
if (endExclusive > len)
throw new IndexOutOfBoundsException("endExclusive=" + endExclusive + " > s.length=" + len);
}
I've been using a helper class that contains a static Queue of parsed values, and I find it to look quite clean. This would be the helper class could look like:
public static class Parsing {
// Could optimise with specific queues for primitive types
// and also using a circular queue, instead of LinkedList
private static final Queue<Number> QUEUE = new LinkedList<Number>();
public static boolean parseInt(String value) {
// Could implement custom integer parsing here, which does not throw
try {
QUEUE.offer(Integer.parseInt(value));
return true;
}
catch (Throwable ignored) {
return false;
}
}
public static int getInt() {
return QUEUE.remove().intValue(); // user's fault if this throws :)
}
}
And then in code, you use it like this:
public Vector3 parseVector(String content) {
if (Parsing.parseInt(content)) {
return new Vector3(Parsing.getInt());
}
else {
String[] parts = content.split(",");
if (Parsing.parseInt(parts[0]) && Parsing.parseInt(parts[1]) && Parsing.parseInt(parts[2])) {
// the queue ensures these are in the same order they are parsed
return new Vector3(Parsing.getInt(), Parsing.getInt(), Parsing.getInt());
}
else {
throw new RuntimeException("Invalid Vector3");
}
}
}
The only problem with this, is that if you use multiple calls like i did above, but maybe the last one fails, then you'd have to roll back or clear the queue
Edit: You could remove the above problem and include some thread safely, by making the class non-static and, maybe for slightly cleaner code, make the class implement AutoCloseable so that you could do something like this:
public Vector3 parseVector(String content) {
try (Parsing parser = Parsing.of()) {
if (parser.parseInt(content)) {
return new Vector3(parser.getInt());
}
else {
String[] parts = content.split(",");
if (parser.parseInt(parts[0]) && parser.parseInt(parts[1]) && parser.parseInt(parts[2])) {
// the queue ensures these are in the same order they are parsed
return new Vector3(parser.getInt(), parser.getInt(), parser.getInt());
}
else {
throw new RuntimeException("Invalid Vector3");
}
}
}
}
You can use a Null-Object like so:
public class Convert {
#SuppressWarnings({"UnnecessaryBoxing"})
public static final Integer NULL = new Integer(0);
public static Integer convert(String integer) {
try {
return Integer.valueOf(integer);
} catch (NumberFormatException e) {
return NULL;
}
}
public static void main(String[] args) {
Integer a = convert("123");
System.out.println("a.equals(123) = " + a.equals(123));
System.out.println("a == NULL " + (a == NULL));
Integer b = convert("onetwothree");
System.out.println("b.equals(123) = " + b.equals(123));
System.out.println("b == NULL " + (b == NULL));
Integer c = convert("0");
System.out.println("equals(0) = " + c.equals(0));
System.out.println("c == NULL " + (c == NULL));
}
}
The result of main in this example is:
a.equals(123) = true
a == NULL false
b.equals(123) = false
b == NULL true
c.equals(0) = true
c == NULL false
This way you can always test for failed conversion but still work with the results as Integer instances. You might also want to tweak the number NULL represents (≠ 0).
You could roll your own, but it's just as easy to use commons lang's StringUtils.isNumeric() method. It uses Character.isDigit() to iterate over each character in the String.
You shouldn't use Exceptions to validate your values.
For single character there is a simple solution:
Character.isDigit()
For longer values it's better to use some utils. NumberUtils provided by Apache would work perfectly here:
NumberUtils.isNumber()
Please check https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/math/NumberUtils.html
Related
As part of my AP computer science project, I decided to get a polynomial from a user and it will be able to find the derivative of the equation using the power rule.
For example, if the user enters 2X^3+5x^2 it should output 6x^2+10x^1, so the coefficient and degree multiplied together and then the degree is just minus one. This is what I have so far but it's giving me a lot of errors, and tried following the code but don't see anything wrong with it. Thanks for your help.
import java.util.ArrayList;
import java.util.Scanner;
public class Practice {
public static void main(String[] args) {
//input of polynomial
System.out.println("Enter polynomial:");
Scanner sc = new Scanner(System.in);
String polynomialEquation = sc.nextLine();
//A string array list is created with the polynomial
ArrayList<String> equationArr = new ArrayList<String>();
for (int i = 0; i<polynomialEquation.length(); i++) {
equationArr.add(polynomialEquation.substring(i, i+1));
}
ArrayList<String> intStrings = new ArrayList<String>();
//separate the numbers from the list
for(int i =0; i<equationArr.size(); i++) {
if (equationArr.get(i).equals("1") || equationArr.get(i).equals("2") || equationArr.get(i).equals("3") ||equationArr.get(i).equals("4") ||equationArr.get(i).equals("5") ||
equationArr.get(i).equals("6") || equationArr.get(i).equals("7") || equationArr.get(i).equals("8") || equationArr.get(i).equals("9") || equationArr.get(i).equals("0"))
{
String addVal = equationArr.get(i);
intStrings.add(addVal);
equationArr.remove(i);
}
}
//convert string integers to integers
ArrayList<Integer> deriveInt = new ArrayList<Integer>(intStrings.size());
for (String myInt : intStrings)
{
deriveInt.add(Integer.valueOf(myInt));
}
//derive coefficiants
for (int i = 0; i<deriveInt.size()-1;i +=2) {
deriveInt.set(i, deriveInt.get(i)*deriveInt.get(i+1));
}
//derive exponent
for(int i = 1; i< deriveInt.size(); i +=2) {
deriveInt.set(i,deriveInt.get(i)-1);
}
//convert integer back to string
ArrayList<String> stringDerive = new ArrayList<String>();
for (Integer myInt2 : deriveInt)
{
stringDerive.add(String.valueOf(myInt2));
}
//get the signs from the original equation
ArrayList<String> sign = new ArrayList<String>();
for(int i =0; i<equationArr.size(); i++) {
if(equationArr.get(i).equals("+") || equationArr.get(i).equals("-")) {
sign.add(equationArr.get(i));
}
}
int totalSize = stringDerive.size() * 2 + equationArr.size();
for (int i = 0; i<totalSize-1; i=+2) {
int countSign= 0;
System.out.print(stringDerive.get(i));
System.out.print("x^");
System.out.print(stringDerive.get(i+1));
System.out.print(equationArr.get(countSign));
}
}
}
Polynomials are composed of monomials. In your example these are 2X^3 and 5x^2. One of approach to solving your problem is writing the Monom class and Polynom class. I'll give you a skeleton so you can practice.
public class Helper {
private class Monom{
private int coefficient;
private int degree;
public Monom(int coefficient, int degree){
this.coefficient = coefficient;
this.degree = degree;
}
public Monom(String input){
//TODO parse input. E.g Monom("6x^2) --> this.coefficient = 6...
//TODO validate input
}
public Monom derivate(final Monom monom){
return new Monom(monom.getCoefficient() * monom.getDegree(), monom.getDegree() - 1);
}
public int getCoefficient() {
return coefficient;
}
public int getDegree() {
return degree;
}
#Override
public String toString(){
return this.coefficient + "x^" + this.degree;
}
}
//skeleton
private class Polynom{
private List<Monom> polynom; //holder of monoms
//TODO rest of code including constructors, validate, derivate...
public Polynom(List<Monom> monoms){
this.polynom = monoms;
}
public Polynom derivate(Polynom input){
List<Monom> temp = new ArrayList<>();
for (Monom monom: polynom){
temp.add(monom.derivate(monom));
}
return new Polynom(temp);
}
}
public static void main(String[] args) {
//TODO test code
List<Monom> monoms = new ArrayList<>();
//TODO rest of code like:
// Polynom myPolynom = new Polynom(List<Monom> monoms);
//...
}
}
Like I said, this is just a code you have to upgrade... Good luck.
welcome to Stack Overflow and the wonderful world of programming! On a personal note, I started coding in high school with APCS too :)
Your question is arguably a bit too broad for this site. For example, you mentioned the code is "giving me a lot of errors": a better question would include the inputs you've tried and the specific output you're seeing and what you expected instead. I still want to help you though, so I'll give you some feedback and we can work through a few revisions.
First, I see that you've divided your program into sections using comments. This is a great instinct! You've decomposed the larger problem into smaller problems in a way that communicates your intent.
input of polynomial
A string array list is created with the polynomial
separate the numbers from the list
convert string integers to integers
derive coefficiants
derive exponent
convert integer back to string
get the signs from the original equation
However, it still leaves us with the problem of having a large main method to understand. So for your next revision, you should fix that by breaking it up into smaller methods. You can start by moving each of these "steps" into its own method, then call each of them from main. To help you get started, here's what it would look like with your first "step" extracted:
public class Practice {
public static String readPolynomial() {
System.out.println("Enter polynomial:");
Scanner sc = new Scanner(System.in);
String polynomialEquation = sc.nextLine();
return polynomialEquation;
}
public static void main(String[] args) {
String polynomialEquation = readPolynomial();
//A string array list is created with the polynomial
...
}
}
I think you'll find that this really improves your understanding of both your code and the problem you're trying to solve. Don't be afraid to change the steps based on that new understanding. It's no coincidence that the buggy or unfocused areas of your code are the areas you'll struggle the most to name. Try to focus on the problem, rather than your implementation. For instance, my first step would probably be a combination of your first few. Things like parsing the input String and then converting from Strings to Integer don't have much to do with polynomials or derivatives. So for readPolynomial I would prefer:
public static ArrayList<Integer> readPolynomial() {
The other big benefit of this refactor is that it will be much easier for you to test that each step is working the way you want it to. It gives you much more fine-grained control because you can test each method individually, rather than only being able to test by running the entire program. It will be much easier to isolate, understand, and fix each individual bug.
Another big thing: please provide some more sample inputs! Not only will this help clarify requirements, but we can use them as test cases later.
Here's some functioning code to help you, please don't just take it for granted but read it and understand what is happening. If you have any questions on it please ask. It could use some cleanup but hopefully it's still understandable.
One minor thing to note is that sign is attached to the expressions (as it kinda should be) so you could just + all the expressions together and it would be valid. But if you want to avoid having an answer like 6x^2 + -10y^4 and would rather have 6x^2 - 10y^4 then you'd have to check if the expressions are negative when building the answer with them.
public class Test {
public static void main(String[] args) {
// input requires all constants to be fully resolved
// eg. no '3^2^1^3', instead it should be '9'
// eg. no '5*2x', instead it should be '10x'
// mess around with the input to test
String s = "2x^3+5x^2";
List<DerivableExpression> list = parseDeriveableExpressions(s);
List<DerivableExpression> derivatives = new ArrayList<>();
for(DerivableExpression de : list)
derivatives.add(de.getDerivative());
System.out.println(String.join("+", derivatives)); // 6x^2+10x^1
}
private static List<DerivableExpression> parseDeriveableExpressions(String s) {
// remove all spaces and lowercase everything
s = s.replace(" ", "");
List<DerivableExpression> list = new ArrayList<>();
char var = ' ';
StringBuilder constBuff = new StringBuilder();
StringBuilder powerBuff = new StringBuilder();
boolean parsingPower = false;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '+' || c == '-') {
if (parsingPower && powerBuff.length() == 0) {
// at the start of the power expression
if (c == '-')
powerBuff.append(c);
} else {
// either not parsing a power or not at the start of the power
// this is a +/- after the power, terminating the expression
parsingPower = false;
int constant = 1;
if (constBuff.length() > 0) {
constant = Integer.parseInt(constBuff.toString());
constBuff.setLength(0);
}
if (var != ' ' && constant != 0) {
int power = 1;
if (powerBuff.length() > 0)
power = Integer.parseInt(powerBuff.toString());
list.add(new VariableExpression(constant, var, power));
} else {
list.add(new ConstantExpression(constant));
}
powerBuff.setLength(0);
var = ' ';
// append the sign for the next expression
if (c == '-')
constBuff.append(c);
}
} else if ('0' <= c && c <= '9') {
if (parsingPower)
powerBuff.append(c);
else
constBuff.append(c);
} else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) {
if (constBuff.length() == 0 ||
(constBuff.length() == 1 && constBuff.charAt(0) == '-'))
constBuff.append("1");
var = c;
} else if (c == '^') {
parsingPower = true;
}
}
// add the last expression
int constant = 1;
if (constBuff.length() > 0) {
constant = Integer.parseInt(constBuff.toString());
constBuff.setLength(0);
}
if (var != ' ') {
int power = 1;
if (powerBuff.length() > 0) {
power = Integer.parseInt(powerBuff.toString());
powerBuff.setLength(0);
}
list.add(new VariableExpression(constant, var, power));
var = ' ';
} else {
list.add(new ConstantExpression(constant));
}
return list;
}
private static interface DerivableExpression {
public abstract DerivableExpression getDerivative();
}
private static class VariableExpression implements DerivableExpression {
private final int constant;
private final char variable;
private final int power;
public VariableExpression(int constant, char variable, int power) {
this.constant = constant;
this.variable = variable;
this.power = power;
}
#Override public VariableExpression getDerivative() {
return new VariableExpression(constant * power, variable, power - 1);
}
#Override public String toString() { return constant + "" + variable + "^" + power; }
}
private static class ConstantExpression implements DerivableExpression {
private final int constant;
public ConstantExpression(int constant) {
this.constant = constant;
}
#Override public DerivableExpression getDerivative() { return this; }
#Override public String toString() { return Integer.toString(constant); }
}
}
the code below is meant to count each time character 'x' occurs in a string but it only counts once ..
I do not want to use a loop.
public class recursionJava
{
public static void main(String args[])
{
String names = "xxhixx";
int result = number(names);
System.out.println("number of x: " + result);
}
public static int number (String name)
{
int index = 0, result = 0;
if(name.charAt(index) == 'x')
{
result++;
}
else
{
result = result;
}
index++;
if (name.trim().length() != 0)
{
number(name);
}
return result;
}
}
You could do a replacement/removal of the character and then compare the length of the resulting string:
String names = "xxhixx";
int numX = names.length() - names.replace("x", "").length(); // numX == 4
If you don't want to use a loop, you can use recursion:
public static int number (String name)
{
if (name.length () == 0)
return 0;
int count = name.charAt(0)=='x' ? 1 : 0;
return count + number(name.substring(1));
}
As of Java 8 you can use streams:
"xxhixx".chars().filter(c -> ((char)c)=='x').count()
Previous recursive answer (from Eran) is correct, although it has quadratic complexity in new java versions (substring copies string internally). It can be linear one:
public static int number(String names, int position) {
if (position >= names.length()) {
return 0;
}
int count = number(names, position + 1);
if ('x' == names.charAt(position)) {
count++;
}
return count;
}
Your code does not work because of two things:
Every time you're calling your recursive method number(), you're setting your variables index and result back to zero. So, the program will always be stuck on the first letter and also reset the record of the number of x's it has found so far.
Also, name.trim() is pretty much useless here, because this method only removes whitespace characters such as space, tab etc.
You can solve both of these problems by
making index and result global variables and
using index to check whether or not you have reached the end of the String.
So in the end, a slightly modified (and working) Version of your code would look like this:
public class recursionJava {
private static int index = 0;
private static int result = 0;
public static void main(String[] args) {
String names = "xxhixx";
int result = number(names);
System.out.println("number of x: " + result);
}
public static int number (String name){
if(name.charAt(index) == 'x')
result++;
index++;
if(name.length() - index > 0)
number(name);
return result;
}
}
You can use StringUtils.countMatches
StringUtils.countMatches(name, "x");
Surely the solution to this is the following:
public long myFunc(String name) throws Exception {
for(int i=0;i<amount;i++){
if(this.otherString[i].equals(name))
return longArray[i];
}
throw new Exception("Not found");
}
However, this does not seem to be the case.
You can use Guava, then your code can looks like this
String[] stringArray = {"s1", "s2", "s3"};
int index = Iterators.indexOf(Iterators.forArray(stringArray), new Predicate<String>() {
#Override
public boolean apply(String input) {
return input.equals("s2");
}
});
or simpler
int index = Arrays.asList(stringArray).indexOf("s2");
Your code can also look like this
public class Finder {
private String[] stringArray = {"s1", "s2", "s3"};
public int findIndex(String name) {
for (int i = 0; i < stringArray.length; i++) {
if (stringArray[i].equals(name))
return i;
}
throw new RuntimeException("Not found");
}
public static void main(String... s) {
int index = new Finder().findIndex("s1");
System.out.println(index);
}
}
You can either run your code through a debugger and find out why it doesn't work, or add some println traces to your original code and you'll see what the problem is:
public long myFunc(String name) throws Exception {
System.out.println("Looking for: " + name);
for (int i = 0; i < amount; i++){
if(this.otherString[i].equals(name))
return longArray[i];
System.out.printf("%4d: \"%s\": No match.%n", i, this.otherString[i]);
}
for (int i = amount; i < this.otherString.length; i++)
System.out.printf("%4d: \"%s\": Not checked.%n", i, this.otherString[i]);
throw new Exception("Not found");
}
By the way, make sure you are correctly interpreting the method's behaviour. Could it be that it's finding it but throwing an ArrayIndexOutOfBoundsException because i is greater than longArray.length, and you misinterpret that as the exception you are explicitly throwing?
Turns out '\u0000' was at the end of the string that was meant to be equal. This does not show in printing. Next time I will be more ruthless in the inspection of the debugging. Thank you for all the suggestions though, and sorry for wasting your time.
This might be completely wrong, but isn't the problem just missing curly brackets in the if statement? I am new to the java language and the example is probably messy, but it uses the same structure from your question and works just fine:
public class random_class {
public static void main(String[] args) {
// TODO Auto-generated method stub
String[] a = new String[] {"hi!", "hello world!", "ho ho ho world!"};
int b = getHWIndex(a);
System.out.println(b);
}
public static int getHWIndex(String[] stringArray){
int i;
Boolean test = false;
for(i=0;i<stringArray.length;i++){
if(stringArray[i].equals("hello world!")){
test = true;
break;
}
}
if(test == true){
return i;}else{
return i = 0; // this is not a good answer...
//but as you return an int I could not think on a quick way to fix the return when there is no match.
}
}
}
I've got a problem with my Java program. There is an error in my code on line 16 (t = T[i];) which implies an error on line 12. It says :
Syntax error on token "=",VariableInitializer expected after this token.
Could I have some help ?
public class Ngrams {
public static boolean estPrefixe(String t, String s) {
int Longs = s.length();
if (t.substring(0, Longs) == s) {
return true;
} else {
return false;
}
}
public static int nbOccurences(String[] T, String s) {
int compteur = 0;
String t = null;
for (int i = 0; i < T.length; i++) {
t = T[i];
if (estPrefixe(t, s)) {
compteur++;
}
return compteur;
}
}
Notwithstanding the fact that you're comparing Strings with == instead of .equals(), and that a right bracket seems to have gone AWOL, at the end of your program, you're "missing" a return statement in nbOccurences. Even though you have one in the for-loop, if you never enter the loop, you don't return anything.
Move your return statement down one line, outside of the loop instead.
public static int nbOccurences(String[] T, String s) {
int compteur = 0;
String t = null;
for (int i = 0; i < T.length; i++) {
t = T[i];
if (estPrefixe(t, s)) {
compteur++;
}
}
return compteur;
}
The method nbOccurences does not always return an int value. If T is null or empty (length = 0) no value is returned. So you should add another return statement after the for loop.
As others mentioned already you should use equals to compare strings. This however, is not producing a syntax error.
Well there's a serious bug in this line:
if (t.substring(0, Longs) == s) {
This test will always be false, because == compares object references, not values. Change it to:
if (t.substring(0, Longs).equals(s)) {
But the whole method is pointless. Change it to:
public static boolean estPrefixe(String t, String s) {
return t.startsWith(s);
}
Or just delete the method altogether because it adds no value whatsoever.
First my call back to increment I know is not correct. I am not sure what to do. I need increment to use temp when it hits that case that requires that call back. I can't change increment to pass a parameter into it because the graders test script wont allow for it. The second problem is that it wont increment any input. For instance if you just call increment on the number 23 it just returns 23. The test script for the grader looks something like this:
public class TestBigNaturalSimple {
public static void main(String[] args) {
BigNatural b1 = new BigNatural(); // default constructor
BigNatural b2 = new BigNatural(23); // one-argument int constructor
BigNatural b3 = new BigNatural("346"); // one-argument String constructor
BigNatural b4 = new BigNatural(b2); // one-argument BigNatural
// constructor
b1.increment();
b3.decrement();
System.out.println(b1.toString()); // should print out 1
System.out.println(b4.toString()); // should print out 23
}
}
My code is:
public class BigNatural {
private String num;
public BigNatural(String input) {
num = input;
}
public BigNatural(BigNatural input) {
num = input.toString();
}
public BigNatural(Integer input) {
num = input.toString();
}
public BigNatural() {
Integer i = 0;
num = i.toString();
}
public void increment() {
Integer first = 0;
Character ch = num.charAt(num.length()-1);
Integer last = Character.digit(ch, 10);
if (num.length() > 1)
{
if (last < 9) {
last++;
}
else
{
if (num.length() >= 2)
{
last = 0;
String temp = new String(num.substring(0, num.length()-2));
increment();
}
else
{
last++;
}
}
}
else
{
if (last < 9)
{
last++;
}
else
{
last = 0;
first = 1;
}
}
String t = last.toString();
if (first > 0)
{
String x = first.toString();
num.concat(x);
}
num.concat(t);
}
public void decrement() {
Character ch = num.charAt(num.length()-1);
Integer last = Character.digit(ch, 10);
if(num.length() > 1)
{
if(last == 0)
{
String temp = new String(num.substring(0, num.length()-2));
decrement();
}
else
{
last--;
}
}
else
{
if(last > 0)
{
last--;
}
else
{
last = 0;
}
}
String t = last.toString();
num.concat(t);
}
public String toString() {
return num;
}
}
That has to be the most complicated way to increment a number I have ever seen. ;) I assume you have to do it that way.
From what I can see you don't change num anywhere. I would expect this to be obvious if you used a debugger. ;)
Try using num = num.concat(t) if you expect num to change.
Note: String is immutable so you cannot change it, you can only replace it.
EDIT: Here is a version provided for your own interest. Your professor will know you didn't write this, so don't copy it. ;)
public void increment() {
num = increment(num);
}
private static String increment(String s) {
if (s.length() <= 0) return "1";
char ch = s.charAt(s.length() - 1);
String top = s.substring(0, s.length() - 1);
return ch < '9' ? top + ++ch : increment(top) + '0';
}
Strings are immutable in Java. Hence, the code
num.concat(t);
in your increment method will not do what you expect.
First, apply the rule don't repeat yourself:
to increment is to add 1
to decrement is to add -1
Thus you simply need to write on function that takes a number as input and add it to your BigNatural:
public void increment() {
add(1);
}
public void decrement() {
add(-1);
}
private void add(int i) {
// Your homework here ...
// You will have only one function to debug and correct, not 2
}
Second: as pointed in other answers, num.concat(t); does not do what you expect, you'll need num = num.concat(t);. Always refer to the Java documentation when you use a function you don't know. If you don't have an editor that allows you to debug your programs, I strongly suggest you get one: Eclipse for instance but other editors might be better as learning tool. The added benefit is that the tools will format the code for you, warn you about lots of mistakes, ...