2

I have a main class that is supposed to print the output to the console...

E.g. If the line contains A and B, I would need to print "Apple & Banana" on to the console, but with my current code, it prints as "Apple & Banana & "

I would do this in the main method by first instantiating an object of that class, i.e.

VeggiesAndFruits myVeg1 = new VeggiesAndFruits(AB);
VeggiesAndFruits myVeg2 = new VeggiesAndFruits(A);
System.out.println(myVeg1.getDescription());
System.out.println(myVeg2.getDescription());

Sample of code:

public class VeggiesAndFruits
{
String line;

public VeggiesAndFruits(String line)
{
this.line = line;
}

public String getDescription()
    {
        String description = "";

        if(line.contains("A"))
        {
            description += "Apple & ";
        }
        if(line.contains("B"))
        {
            description += "Banana & ";
        }
        if(line.contains("C"))
        {
            description += "Carrot & ";

        return description;
}
}
  • Your code has some syntax errors - missing double quotes `"` in the `main` method, and a missing brace `}` in the `getDescription` method. – kaya3 Feb 03 '20 at 03:31
  • 2
    Consider using [String.join](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#join-java.lang.CharSequence-java.lang.CharSequence...-). – Andrew S Feb 03 '20 at 03:39
  • One option is to not add the `&` until you need it - i.e. keep a count and add an ampersand before your string if the count is > 1. Here is something similar: https://stackoverflow.com/a/43380662/857132 – John3136 Feb 03 '20 at 03:46
  • Everyone got so excited to answer your question, hehe! – CausingUnderflowsEverywhere Feb 03 '20 at 03:49

6 Answers6

5

If using Java 8+, I suggest using a StringJoiner here. As the Javadoc says, StringJoiner is used to construct a sequence of characters separated by a delimiter. Like,

public String getDescription() {
    StringJoiner sj = new StringJoiner(" & ");

    if (line.contains("A")) {
        sj.add("Apple");
    }
    if (line.contains("B")) {
        sj.add("Banana");
    }
    if (line.contains("C")) {
        sj.add("Carrot");
    }
    return sj.toString();
}

And in earlier versions of Java (5+) you can use StringBuilder (and "glue" as kaya3 noted).

public String getDescription() {
    StringBuilder sb = new StringBuilder();
    String glue = "";
    if (line.contains("A")) {
        sb.append("Apple");
        glue = " & ";
    }
    if (line.contains("B")) {
        sb.append(glue);
        sb.append("Banana");
        glue = " & ";
    }
    if (line.contains("C")) {
        sb.append(glue);
        sb.append("Carrot");
    }
    return sb.toString();
}

Prior to Java 5, you could use a StringBuffer like

public String getDescription() {
    StringBuffer sb = new StringBuffer();
    String glue = "";
    if (line.contains("A")) {
        sb.append("Apple");
        glue = " & ";
    }
    if (line.contains("B")) {
        sb.append(glue);
        sb.append("Banana");
        glue = " & ";
    }
    if (line.contains("C")) {
        sb.append(glue);
        sb.append("Carrot");
    }
    return sb.toString();
}
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
2

In Java 8+, use StringJoiner:

public String getDescription() {
    StringJoiner description = new StringJoiner(" & ");
    if (line.contains("A"))
        description.add("Apple");
    if (line.contains("B"))
        description.add("Banana");
    if (line.contains("C"))
        description.add("Carrot");
    return description.toString();
}

In Java 5+, use StringBuilder and if statements:

public String getDescription() {
    StringBuilder description = new StringBuilder();
    if (line.contains("A")) {
        description.append("Apple");
    }
    if (line.contains("B")) {
        if (description.length() != 0)
            description.append(" & ");
        description.append("Banana");
    }
    if (line.contains("C")) {
        if (description.length() != 0)
            description.append(" & ");
        description.append("Carrot");
    }
    return description.toString();
}

Or, as pointed out by kaya3:

public String getDescription() {
    StringBuilder description = new StringBuilder();
    String sep = "";
    if (line.contains("A")) {
        description.append(sep).append("Apple");
        sep = " & ";
    }
    if (line.contains("B")) {
        description.append(sep).append("Banana");
        sep = " & ";
    }
    if (line.contains("C")) {
        description.append(sep).append("Carrot");
        sep = " & ";
    }
    return description.toString();
}

Or the way the question code is trying to do it:

public String getDescription() {
    StringBuilder description = new StringBuilder();
    if (line.contains("A"))
        description.append("Apple & ");
    if (line.contains("B"))
        description.append("Banana & ");
    if (line.contains("C"))
        description.append("Carrot & ");
    if (description.length() != 0)
        description.setLength(description.length() - 3); // remove final " & "
    return description.toString();
}

Test

System.out.println(new VeggiesAndFruits("").getDescription());
System.out.println(new VeggiesAndFruits("A").getDescription());
System.out.println(new VeggiesAndFruits("B").getDescription());
System.out.println(new VeggiesAndFruits("C").getDescription());
System.out.println(new VeggiesAndFruits("AB").getDescription());
System.out.println(new VeggiesAndFruits("AC").getDescription());
System.out.println(new VeggiesAndFruits("BC").getDescription());
System.out.println(new VeggiesAndFruits("CBA").getDescription());

Output (same for all 4 solutions above)


Apple
Banana
Carrot
Apple & Banana
Apple & Carrot
Banana & Carrot
Apple & Banana & Carrot
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • 2
    Re: the Java 5 way, there's a neat solution which avoids the extra `if` statement; you can declare `String glue = "";` at the start, unconditionally append `glue` before each item, and then unconditionally assign `glue = " & ";` after each item. – kaya3 Feb 03 '20 at 03:50
  • @kaya3 Added to answer. Thanks. – Andreas Feb 03 '20 at 03:55
0

You can try using the int lastIndexOf(int ch) method on a string.

For example:

int index=description.lastIndexOf('&');

Then you can take a substring from the main string using this index to remove the last &.

String newDescription = description.substring(0, index);
Harshvardhan Joshi
  • 2,855
  • 2
  • 18
  • 31
0

Please have a look on a very important, valuable and old-but-gold class in Java called StringBuilder.

There are two points you could improve here:

  1. To improve your memory handling in Java when you work with String objects: The concept of StringBuilder is quite straightforward and clear - to implement Builder Pattern and not to keep creating unnecessary new String objects after each concatenation of String values. This may not be obvious betterment when you have two or three Strings, but it's a huge advantage when you have many more Strings.. besides, it's way clearer code;

  2. StringBuilder API provides methods out of the box on how to handle (concatenate, replace, substring and etc.) your String values. You can, for instance, use getChars(..), indexOf(..), lastIndexOf(..) and many more ready methods for your convenience.

Giorgi Tsiklauri
  • 9,715
  • 8
  • 45
  • 66
  • Hey Giorgi, could you add some more details to explain how StringBuilder can be used? – CausingUnderflowsEverywhere Feb 03 '20 at 03:48
  • 2
    Please have a look on another very important, valuable and old-but-gold class in Java called [`StringJoiner`](https://docs.oracle.com/javase/8/docs/api/java/util/StringJoiner.html). – Andreas Feb 03 '20 at 03:51
  • Hey, @CausingUnderflowsEverywhere. I thought giving a reference to API is the most clear, and obvious way of providing info, as StringBuilder isn't that complicated class to understand; however, I still have edited my answer upon your remark, and I hope it is better now. – Giorgi Tsiklauri Feb 03 '20 at 03:55
  • Hey, Java already uses StringBuilder under the hood when += string concatenation is used. I'll try to find you a source of that. – CausingUnderflowsEverywhere Feb 03 '20 at 03:58
  • https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.18.1 – CausingUnderflowsEverywhere Feb 03 '20 at 04:00
  • @CausingUnderflowsEverywhere That's changed in Java 9+. I also don't think it would use the same StringBuilder across multiple statements in different blocks. – kaya3 Feb 03 '20 at 04:00
  • @CausingUnderflowsEverywhere, it's very unlikely due to the structure and architecture of how String works behind the scenes. You're then losing several fundamental aspects of String. But Ok, please provide. – Giorgi Tsiklauri Feb 03 '20 at 04:01
  • @Giorgi Tsiklauri https://dzone.com/articles/string-concatenation-performacne-improvement-in-ja and https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.18.1 – CausingUnderflowsEverywhere Feb 03 '20 at 04:02
  • @CausingUnderflowsEverywhere please read more carefully what you have posted as a reference. :) – Giorgi Tsiklauri Feb 03 '20 at 04:04
  • So the behaviour has changed in java 9, https://www.guardsquare.com/en/blog/string-concatenation-java-9-untangling-invokedynamic – CausingUnderflowsEverywhere Feb 03 '20 at 04:05
  • Again: please take a closer look on the references you post. First `docs.oracle` link has absolutely nothing to do on this topic, on the contrary - it emphasizes concatenation; second link states, that in some simple static concatenations, compiler `MAY` do a trick. That has nothing to do with newer JDK builds having `newer way` of auto-casting Strings to StringBubilder objects. Good luck. – Giorgi Tsiklauri Feb 03 '20 at 04:09
  • According to your docs, for `constant concatenations` (which is just simple two strings joining), compiler help might work, but I'm not sure what lies inside and what is the bytecode javac generates in that case. – Giorgi Tsiklauri Feb 03 '20 at 04:11
0

Create a description builder class in your current class to cleanly handle generating your description. It will have one main method for adding content, and internally it will decide when to put an & sign and spaces if necessary using a putContent method that just creates the beginning of the description, and an appendContent method that adds more parts to the description.

class DescriptionBuilder {
    private String description = "";

    public DescriptionBuilder() {
    }

    //Use this method when adding content.
    public void addContent(String content) {
        if (description.isEmpty()) {
            putContent(content);
        } else {
            appendContent(content);
        }
    }

    //Get the built description
    @Override
    public String toString() {
        return description;
    }

    //Internally decided to create the start of the description
    private void putContent(String content) {
        description = content;
    }

    //Internally decided it's time to add more to the existing description
    private void appendContent(String content) {
        description += " & " + content;
    }
}

Then modify your getDescription method to use the description builder.

public String getDescription() {
        DescriptionBuilder descriptionBuilder = new DescriptionBuilder();

        if (line.contains("A")) {
            descriptionBuilder.addContent("Apple");
        }
        if (line.contains("B")) {
            descriptionBuilder.addContent("Banana");
        }
        if (line.contains("C")) {
            descriptionBuilder.addContent("Carrot");
        }
        return descriptionBuilder.toString();
    }
0

Without changing your sub class, In the main class you can remove last two character from out put (remove "&" and "final space" ), Also you missing double quotes " in the main method

VeggiesAndFruits myVeg1 = new VeggiesAndFruits(AB);

have to change as

VeggiesAndFruits myVeg1 = new VeggiesAndFruits("AB");

using String substring method you can remove last 2 charcter.

public static void main(String[] args) {
        VeggiesAndFruits myVeg1 = new VeggiesAndFruits("AB");
        String result ="";
        String str=myVeg1.getDescription();

        if ((str != null) && (str.length() > 0)) {
            result = str.substring(0, str.length() - 2);
        }
        System.out.println(result);         
    }
Rayan Aradha
  • 500
  • 1
  • 4
  • 13