Могу ли я иметь макросы в исходных файлах Java - PullRequest
47 голосов
/ 29 июня 2011

В моей программе я читаю целые числа из консоли много раз.Каждый раз мне нужно набрать эту строку.

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

Я привык к C / C ++, и мне интересно, могу ли я определить что-то вроде

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

, а затемв любом месте моей Java-программы я могу читать форму консоли как

int a = new READINT;

Но я читаю книги форм Java не поддерживает макросы.

Кто-нибудь, пожалуйста, объясните мне, почему это так, и я могу сделать это любым другим способом.

Ответы [ 8 ]

143 голосов
/ 29 июня 2011

Вы можете , но вы не должны .

не должны часть:

Вы не следует , потому что использование препроцессора таким образом считается плохой практикой для начала, и существуют лучшие и более идиоматические способы решения этого варианта использования.

может часть: (*)

Сама Java не поддерживает макросы.С другой стороны, вы могли бы передать исходный код через препроцессор C (для краткости CPP), как это делает цепочка компиляции C / 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 команда:

$ 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().)

И, наконец, анекдот

Я сам однажды использовал подход предварительной обработки CPP для кода Java!Я создавал задание по программированию для курса.Я хотел иметь возможность легко извлечь фрагмент кода из эталонного решения.Поэтому я просто использовал несколько #ifdef s, чтобы отфильтровать «секретные» части решения.Таким образом, я мог бы поддерживать эталонное решение и легко восстановить кодовый скелет.


Этот пост был переписан как статья здесь .


(*) Так как я терпеть не могу отвечать на вопросы с «вы не должны».Кроме того, у некоторых будущих читателей могут быть веские причины для желания использовать cpp вместе с исходными кодами Java!

12 голосов
/ 29 июня 2011

Нет. Java (язык) не поддерживает какие-либо макросы.

Однако некоторые конструкции можно подделать или обернуть. Хотя пример глупый ( почему вы каждый раз создаете новый сканер!?!?! ), ниже показано, как этого достичь:

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

Но намного лучше:

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

Удачного кодирования.


Для комментария:

Статические методы могут быть вызваны без необходимости вызова объекта. Однако в большинстве случаев уже находится в объекте . Рассмотрим:

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();
   }
}
2 голосов
/ 29 июня 2011

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();
 }
1 голос
/ 29 июня 2011

Java не поддерживает макросы.IIRC, разработчики языка посчитали, что макросы и полученный предварительный анализатор были ненужным и нежелательным осложнением.

Вместо этого используйте функцию:

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

В другом месте:

Scanner input=new Scanner(System.in);

...


int a=readInt(input);

Также обратите внимание, что я создаю сканер один раз и повторно его использую.

0 голосов
/ 08 апреля 2019

Это можно сделать, например, с помощью Java Primitive Specializations Generator :

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

...

int a = /* READINT */0/**/;
0 голосов
/ 29 июня 2011

Если вы хотите использовать макросы в стиле C, тогда кто-то написал препроцессор http://www.slashdev.ca/javapp/ Я не знаю, насколько он хорош.

0 голосов
/ 29 июня 2011

Используйте класс утилит и статический импорт.

Класс утилит:

package my.utils;

public class ScannerUtils {
  private ScannerUtils() {}

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

Используя класс утилит:

package my.examples;

import static my.utils.ScannerUtils.*;

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

Как уже говорили другие, выВероятно, следует кэшировать ваш сканер, но это отдельная тема.

0 голосов
/ 29 июня 2011

В Java нет понятия макроса. Если вы делаете это много, плохая идея каждый раз создавать новый Scanner. Определите общедоступную статическую Scanner, а затем используйте ее каждый раз:

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

// Somewhere in your code
YourClass.SCANNER.nextInt();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...