1

I would like to declare a String for a country variable in Java which would only take 2 characters such as IN, DE etc. I am a bit confused so can someone please help me?

If I try to assign a value something like this then it should work: country = "IN" but if I try to assign a value country = "IND" then it should throw an error.

I am a bit familiar with regex but wanted to confirm if there is any built-in String method that would do this.

public class App {
    public static void main(String[] args) {
        String country = "";
        //char[] array = new char[2];
        //String country = new String(array); 
        // String[] country = new String[2];

    }
}
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
BATMAN_2008
  • 2,788
  • 3
  • 31
  • 98
  • 1
    https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#length() – QBrute Feb 04 '21 at 16:03
  • 1
    Create a wrapper class that throws an exception for more than two characters, or just use a char array rather than a string – OneCricketeer Feb 04 '21 at 16:04
  • 1
    Java’s type system does not allow to define such constraints. The closest you can get, is using type annotations and an annotation processor that produces the error. Perhaps, some of the existing checker frameworks are already capable of defining such constraints. – Holger Feb 04 '21 at 16:05
  • 1
    @OneCricketeer Technically correct, conceptually: wrong. If you want to model a country code, then model a country code. Dont model a "two chars only string" and then claim "this models country codes". Meaning: if you decide to create another layer of abstraction, create the most useful one. – GhostCat Feb 04 '21 at 16:09
  • 1
    @Ghost I guess I was more addressing the title than the specific need – OneCricketeer Feb 04 '21 at 16:10
  • 1
    @OneCricketeer how does a char array improve the situation? You can’t limit the length of arrays on assignments either. – Holger Feb 04 '21 at 16:12
  • @Holger `new char[2];`? – OneCricketeer Feb 04 '21 at 16:14
  • 1
    @OneCricketeer I know that you can construct an array of length two, just like you can create a string of length two. The question is, how can you prevent assigning a string or array with a different length. `string = "abc";`, `array = "abc".toCharArray();`, no difference at all. – Holger Feb 04 '21 at 16:16

6 Answers6

3

The simple answer is: you can't.

The String class doesn't have any means that allow you to restrict its objects on assignment. There is no way in Java to get

String someString = "INx":

to fail. This means, you are left with two choices:

  • validation: this means you have utility methods (for example using regular expressions) that check arbitrary string objects and that then tell you whether that string is a valid country abbreviation, like: String countryCode = validate("INx")
  • creating an explicit type

For the later, you would probably look at creating your own enum implementation that simply lists all the valid codes you care about. Or you pick up some existing library.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
3

Not possible, but:

It is good style for values with some business relevance to create classes for them.

A class Country, some usage as:

Country bulgaria = new Country("BG");


public class Country {
   String code;
   public Country(String code) {
       if (code.length() > 2) {
           throw new IllegalArgumentException("At most 2 chars: " + code);
       }
       this.code = code;
   }

If language comes into the picture use Locale.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • 1
    Technically correct, but conceptually wrong, imho. `new Country("")` shouldnt be a valid country, and neither should be `new Country("XY")`... because there are no such countries. – GhostCat Feb 04 '21 at 16:10
  • 1
    @GhostCat I thought of that and a toString, final field, I chose a shorter answer + better error message. – Joop Eggen Feb 04 '21 at 16:14
  • 2
    @GhostCat but `XY` is a valid code, free for user defined purposes… – Holger Feb 04 '21 at 16:24
  • Then take "NQ" ;-) and thanks for the interesting stuff ... https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 – GhostCat Feb 04 '21 at 16:27
1

For a solid solution, I agree with @GhostCat, you can use Locale to get the countries iso codes and you can check if your code exist or not in this list:

final Set<String> isoCountries = Set.of(Locale.getISOCountries());

String country = "DZ";
if (!isoCountries.contains(country.toUpperCase())) {
    throw new IllegalArgumentException(country + " country code not valid.");
}
Naman
  • 27,789
  • 26
  • 218
  • 353
Youcef LAIDANI
  • 55,661
  • 15
  • 90
  • 140
0

for this manner, you can use Regular Expressions here! and Test the expression using! Here is my solution

import java.util.Scanner;

public class StringChecker {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("Please enter 2 char String: ");
        String str = scanner.next();
        String str_valid = "";
        if (str.matches("^[a-zA-Z0-9]{2}$")){
            str_valid = str;
            System.out.println(str_valid);
        }else{
            System.out.println("String is not in 2 chars");
        }

    }
}
  • 1
    You don’t need to specify `^` nor `$` when calling `matches`, as this method does already imply matching from beginning to end. Since the country code does not allow numbers, `matches("[a-zA-Z]{2}")` would be enough. – Holger Feb 04 '21 at 16:22
0

It's not possible as you expecting but you can create validation for that,

String country = sc.next();
if(country.length() == 2){
    //do something 
}else{
    // do something
}

To ask for the string of length = 2 until it gets.

boolean flag = true;
while(flag){
    String country = sc.next();
    if(country.length() == 2){
        flag = false;
        //do something 
    }else{
        // do something
    }
}
XO56
  • 332
  • 1
  • 12
0

Make country a private instance variable and create a setter method, in which you can do validations.

P.S. The following is horrible code. But, I hope it'd help you get the idea.

package com.company;

public class Main {

private static String country = "";
public static void main(String[] args) throws Exception {

    Main m = new Main();
    m.setCountry("DEX");
    System.out.println(country);
}

public void setCountry(String country) throws Exception {

    if(this.country.length() != 0){

        throw new Exception("The country is already set");
    }

    else if (country.length() != 2) {

        throw new Exception("The country string's size cannot be greater than 2");
    }
    else {
        this.country = country;
    }
}
}
arkantos
  • 497
  • 3
  • 14