Can I have macros in Java source files

JavaMacros

Java Problem Overview


In my program I'm reading integers form console many times. Every time, I need to type this line.

new Scanner(System.in).nextInt(); 

I'm used to C/C++ and I'm wondering if I can define something like

#define READINT Scanner(System.in).nextInt(); 

and then, in every place in my java program I can read form console as

int a = new READINT;

But I read form books Java does not support macros.

Someone please explain me why is it so, and can I do this in any other way.

Java Solutions


Solution 1 - Java

You can but you shouldn't.

##The shouldn't part:

You shouldn't because using the pre-processor in that way is considered bad practice to start with, and there are better and more Java-idiomatic ways to solve this use case.


##The can part: (*)

Java itself doesn't support macros. On the other hand, you could pipe the source code through the C pre processor (CPP for short) just like the C/C++ compile chain does.

Here's a demo:

src/Test.java:

#define READINT (new java.util.Scanner(System.in).nextInt())

class Test {
    public static void main(String[] args) {
        int i = READINT;
    }
}

cpp command:

$ cpp -P src/Test.java preprocessed/Test.java

Result:

class Test {
    public static void main(String[] args) {
        int i = (new java.util.Scanner(System.in).nextInt());
    }
}

Compile:

$ javac preprocessed/Test.java


##A better workaround:

You can write your own utility class with a static method instead:

import java.util.Scanner;
class StdinUtil {
    public final static Scanner STDIN = new Scanner(System.in);
    public static int readInt() {
        return STDIN.nextInt();
    }
}

And when you want to use it, you can statically import the readInt method:

import static StdinUtil.readInt; 

class Test {
    public static void main(String[] args) {
        int i = readInt();
    }
}

(or do static import StdinUtil.STDIN; and use STDIN.nextInt().)


##And finally, an anecdote

I myself used the CPP preprocessing approach on Java code once! I was creating a programming assignment for a course. I wanted to be able to easily extract a code skeleton out of the reference solution. So I just used a few #ifdefs to filter out the "secret" parts of the solution. That way I could maintain the reference solution, and easily regenerate the code skeleton.


This post has been rewritten as an article here.


(*) Since I hate answering questions with "you shouldn't". Besides, some future reader may have good reasons for wanting to use the cpp in conjunction with Java sources!

Solution 2 - Java

No. Java (the language) does not support macros of any sort.

However, certain constructs can be faked or wrapped. While the example is silly (why are you creating a new scanner each time!?!?!) the below shows how it can be achieved:

int nextInt() {
   return new Scanner(System.in).nextInt(); 
}
...
int a = nextInt();
int b = nextInt();

But much better:

Scanner scanner = new Scanner(System.in);
int a = scanner.nextInt();
int b = scanner.nextInt();

Happy coding.


For comment:

Static methods can be called without needing an object to invoke them upon. However, in most cases one is already in an object. Consider:

public class Foo {
   static int nextIntStatic() {
     return 13;
   }

   int nextInt() {
     return 42;
   }
   
   void realMain () {
     // okay to call, same as this.nextInt()
     // and we are "in" the object
     int ni = nextInt();
   }

   public static void main(String[] args) {
      // okay to call, is a static method
      int nis = nextIntStatic();
      Foo f = new Foo();
      f.realMain();
   }
}

Solution 3 - Java

Java doesn't support macros simply because the designers of Java chose not to include that functionality. The longer answer is that Java doesn't have a preprocessor the way C/C++ does and cannot perform that functionality that the preprocessor normally would. The way I would implement this is simply create a wrapper class that wraps up the Scanner constructor calls. Perhaps something like

public static int readInt(){
  return new Scanner(System.in).nextInt();
}

Or, better yet,

public class ScannerWrapper{
  private static Scanner instance = null;

  public static int readInt(){
   if (instance == null){
     instance = new Scanner(System.in);
   }
   
   return instance.nextInt();
 }

Solution 4 - Java

Java does not support macros. IIRC, the language designers felt that macros and the resultant preparser was an unnecessary and undesirable complication.

Use a function instead:

public int readInt(Scanner inp) {
    return inp.nextint();
    }

Elsewhere:

Scanner input=new Scanner(System.in);

...


int a=readInt(input);

Note also, that I create the scanner once and reuse it.

Solution 5 - Java

There is no macro concept in Java. If you're doing that a lot, it's a bad idea to instantiate a new Scanner each time. Define a public static Scanner then reuse it each time:

public class YourClass {
  public static final Scanner SCANNER= new Scanner(System.in);
  ...
}

// Somewhere in your code
YourClass.SCANNER.nextInt();

Solution 6 - Java

If you want to use C-Style macros then someone has written a pre-processor http://www.slashdev.ca/javapp/ I have no idea how good it is though.

Solution 7 - Java

You can do this, for example, with Java Primitive Specializations Generator:

/* define READINT //
new Scanner(System.in).nextInt();
// enddefine */

...

int a = /* READINT */0/**/;

Solution 8 - Java

Macros are text-level pre-processing tools that can be badly abused if not carefully designed. Example:

#define MULTIPLY( a, b ) ( a * b )

MULTIPLE(1+2,3+4) will have the result of (1+2*3+4)

Another example

#define SQUARE( a ) ((a) * (a))

int x = 5;
SQUARE(x++);

will increment x twice. ((x++) * (x++))

I think that Java language designers did not buy it for these reasons, because it is meant to be simple.

Solution 9 - Java

Use a utility class and static import.

The utility class:

package my.utils;

public class ScannerUtils {
  private ScannerUtils() {}

  public static int readInt() {
    return new Scanner(System.in).nextInt();
  }
}

Using the utility class:

package my.examples;

import static my.utils.ScannerUtils.*;

class Example {
  void foo() {
    int i = readInt();
  }
}

As others have said, you should probably cache your scanner, but that is a separate topic.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMuthu Ganapathy NathanView Question on Stackoverflow
Solution 1 - JavaaioobeView Answer on Stackoverflow
Solution 2 - Javauser166390View Answer on Stackoverflow
Solution 3 - JavaChris ThompsonView Answer on Stackoverflow
Solution 4 - JavaLawrence DolView Answer on Stackoverflow
Solution 5 - JavaGiannView Answer on Stackoverflow
Solution 6 - JavaGreg ReynoldsView Answer on Stackoverflow
Solution 7 - JavaleventovView Answer on Stackoverflow
Solution 8 - JavaJixuan LIUView Answer on Stackoverflow
Solution 9 - JavaDilum RanatungaView Answer on Stackoverflow