web-dev-qa-db-ja.com

Javaソースファイルにマクロを含めることはできますか

私のプログラムでは、コンソールから整数を何度も読み取っています。毎回、この行を入力する必要があります。

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

私はC/C++に慣れており、次のようなものを定義できるかどうか疑問に思っています

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

そして、私のJavaプログラムのすべての場所で、フォームコンソールを次のように読むことができます

int a = new READINT;

しかし、フォームブックを読んだJavaはマクロをサポートしていません。

誰かがなぜそうなのか説明してください。他の方法でこれを行うことができます。

あなたはcanですが、あなたはshould n'tです。

should n't部分:

あなたはshould n'tのようにプリプロセッサを使用することは 悪い習慣と見なされるためです から、そしてより良いとこのユースケースを解決するためのより多くのJavaイディオマティックな方法。


can部分:(*)

Java自体はマクロをサポートしていません。一方、C /と同様に、 Cプリプロセッサ (略してCPP)を介してソースコードをパイプ処理できます。 C++コンパイルチェーンは行います。

デモは次のとおりです。

_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
_

結果:

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

コンパイル:

_$ javac preprocessed/Test.Java
_


より良い回避策:

代わりに、静的メソッドを使用して独自のユーティリティクラスを作成できます。

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

そして、使用したい場合は、readIntメソッドを静的にインポートできます。

_import static StdinUtil.readInt; 

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

(または_static import StdinUtil.STDIN;_を実行し、STDIN.nextInt()を使用します。)


そして最後に、逸話

私はJava code once!でCPP前処理アプローチを使用しました。コースのプログラミング割り当てを作成していました。参照ソリューションからコードスケルトンを簡単に抽出できるようにしたかったのです。いくつかの_#ifdef_ sを使用して、ソリューションの「秘密」の部分を除外することで、参照ソリューションを維持し、コードスケルトンを簡単に再生成できました。


この投稿は記事 here として書き直されました。


(*)「するべきではない」という質問に答えるのは嫌だから。さらに、将来の読者の中には、Javaソース!とともにcppを使用したい理由があります。

143
aioobe

No。Java(言語)はあらゆる種類のマクロをサポートしません。

ただし、特定の構成要素は偽造またはラップされる可能性があります。この例は馬鹿げています(毎回新しいスキャナーを作成するのはなぜですか!?!?!)。以下にその方法を示します。

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

しかし、muchの方が良い:

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

ハッピーコーディング。


コメント用:

静的メソッドは、それらを呼び出すオブジェクトを必要とせずに呼び出すことができます。ただし、ほとんどの場合、1つはすでにオブジェクトに含まれています。考慮してください:

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();
   }
}
12
user166390

Javaは、Javaの設計者がその機能を含めないことを選択したため、マクロをサポートしません。長い答えは、Javaにはプリプロセッサがありません。 C/C++がプリプロセッサが通常行う機能を実行する方法と実行できない方法これを実装する方法は、単にScannerコンストラクター呼び出しをラップするラッパークラスを作成することです。

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

または、さらに良いことに、

public class ScannerWrapper{
  private static Scanner instance = null;

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

   return instance.nextInt();
 }
2
Chris Thompson

Javaはマクロをサポートしていません。 IIRC、言語設計者は、マクロと結果のプリパーサーは不必要で望ましくない複雑さだと感じました。

代わりに関数を使用します。

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

他の場所:

Scanner input=new Scanner(System.in);

...


int a=readInt(input);

また、スキャナーを一度作成して再利用することに注意してください。

1
Lawrence Dol

これは、たとえば Java Primitive Specializations Generator を使用して実行できます。

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

...

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

Cスタイルマクロを使用したい場合は、誰かがプリプロセッサを書いています http://www.slashdev.ca/javapp/ それがどれほど良いかはわかりません。

0
Greg Reynolds

Javaにはマクロの概念はありません。あなたがそれをたくさんしているなら、毎回新しいScannerをインスタンス化するのは悪い考えです。 public static Scannerを定義してから、毎回それを再利用します:

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

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