Есть ли другой способ реализовать безопасные арифметические операции с переполнением в Java, кроме переопределения арифметических операторов?

Вот мой вопрос. С тех пор, как я изучил Java, я знал, что может существовать арифметическое переполнение и потеря значимости, и компилятор java не будет жаловаться вам на это. Теперь я придумал класс Operation, в котором есть "безопасные от переполнения" целочисленные методы +, -, *. Таким образом, если вычисление переполнится, оно выдаст арифметическое исключение.

public final class Operation{

    public static int aDD (int a, int b) {
    //do something
    if (overflow) {
    throw ArithmeticException("Integer Addition Overflow");
    }
    return a + b;
    }

    public static int sUB (int a, int b) {
    //do something
    if (overflow) {
    throw ArithmeticException("Integer Subtraction Overflow");
    }
    return a - b;
    }

    public static int mUL (int a, int b) {
    //do something
    if (overflow) {
    throw ArithmeticException("Integer Multiplication Overflow");
    }
    return a * b;
    }

    public static long aDD (long a, long b) {
    //do something
    if (overflow) {
    throw ArithmeticException("Long Addition Overflow");
    }
    return a + b;
    }

    public static long sUB (long a, long b) {
    //do something
    if (overflow) {
    throw ArithmeticException("Long Subtraction Overflow");
    }
    return a - b;
    }

    public static long mUL (long a, long b) {
    //do something
    if (overflow) {
    throw ArithmeticException("Long Multiplication Overflow");
    }
    return a * b;
    }
}

Я хочу переопределить исходные арифметические операторы в Java. Так что мне не нужно набирать int c = Operation.aDD(a, b);, чтобы использовать арифметические операции «с защитой от переполнения». Вместо этого мне нужно только набрать int c = a + b;

Однако мне сказали, что переопределение определяемого пользователем оператора невозможно в Java. Итак, есть ли способ добиться того же результата без переопределения оператора в Java. В любом случае это приемлемо, включая смешивание кода Java и C ++. (Обратите внимание, что весь мой код пока написан на Java. Но я думаю, что могу преобразовать его на другой язык с помощью конвертера. Хотя это не гарантирует, что это будет ошибка - бесплатно.) Моя единственная цель - позволить моей старой программе использовать арифметические операции с "безопасным переполнением" без необходимости повторно разлагать все a + b на Operation.aDD(a, b).

Большое спасибо!


person Alex Vong    schedule 08.09.2014    source источник
comment
Вы не можете переопределить операторы в Java. И нельзя смешивать C / C ++ и Java. С некоторыми трудностями вы можете позвонить между ними, но это будет намного уродливее, чем то, что у вас есть сейчас.   -  person Hot Licks    schedule 08.09.2014
comment
Вы можете следовать соглашениям об именах BigDecimal / BigInteger, которые имеют ту же проблему.   -  person Joop Eggen    schedule 08.09.2014


Ответы (3)


Как вы уже выяснили, в java нет перегрузки оператора, которую вы можете использовать.

Отсюда прямо следует, что изменение семантики выражения int a = b + c; в чистом java просто невозможно.

Поскольку вы упомянули, что у вас уже есть код C ++, в зависимости от того, как он структурирован, вы можете создать из него собственную библиотеку (DLL, SO) и использовать JNI для вызова кода C ++. Это становится непрактичным, если ваш код C ++ состоит из множества небольших функций / классов, добавленный беспорядок для собственных вызовов перевесит полезность повторного использования кода. Излишне говорить, что вам понадобится соответствующий двоичный файл для каждой платформы, на которой вы хотите развернуть.

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

Базовые библиотеки Java (например, BigInteger, BigDecimal) идут немного дальше и инкапсулируют свои типы в (обычно неизменяемые) объекты значений, которые (по-прежнему) переносят операции как стандартные вызовы методов. Это делает использование немного более компактным / короче, поскольку компилятор обеспечит немного больше проверки типов, и вам не нужно будет уточнять имена методов с именем класса BigDecimal sum = a.add(b);. Не намного красивее, но это устоявшаяся идиома.

person Durandal    schedule 08.09.2014
comment
Есть ли языковая поддержка синтаксиса Java и перегрузки оператора? Таким образом, если я скопирую в нее свою программу Java, она скомпилируется. Я упоминаю C ++, потому что мне сказали, что C ++ поддерживает перегрузку оператора. Я не имею в виду, что мой код написан на C ++, извините, если я вас запутаю. - person Alex Vong; 09.09.2014
comment
Кроме того, вы упомянули объект значения BigInteger. У меня есть идея. Как насчет того, чтобы использовать MyInteger sum = a.add(b); и MyLong sum = a.add(b);? Затем я узнаю, что у класса Integer и Long есть модификатор final, поэтому я не могу использовать class MyInteger extends Integer и class MyLong extends Long. Следует ли мне скопировать классы Integer и Long и добавить свои собственные методы для создания нового класса? Есть другой способ? - person Alex Vong; 09.09.2014
comment
@AlexVong Core java использует объекты неизменяемых значений (Integer, Long ... BigDecimal ...). Каждая операция создает новый объект; например z = x.add (y); возвращает результат как новый объект z. Идея состоит в том, что вы можете передавать ссылки на объекты значений куда угодно, не беспокоясь об их изменении. - person Durandal; 09.09.2014
comment
Есть ли способ поместить метод в класс Integer? Я хочу добавить в класс метод ADD. Поскольку класс Integer имеет модификатор final, я не могу использовать наследование для его достижения. - person Alex Vong; 09.09.2014
comment
@AlexVong Нет, классы java.lang были сделаны окончательными, чтобы вы не испортили их поведение (помните, что компилятор java полагается на них, обеспечивая точно определенное поведение для автобокса / распаковки). Создайте свой собственный тип, возможно, расширив java.lang.Number. - person Durandal; 09.09.2014

Вы можете использовать Xtend. Вы можете рассматривать Xtend как препроцессор языка Java. Он генерирует чистый, читаемый человеком код Java.

Глава о перегрузке операторов в Xtend. Вот пример определения метода перегрузки для оператора '+' для целых чисел:

def static operator_add(IntVar a, IntVar b) {
    return Operation.add(a, b)
}

Недостатки

Xtend - это тоже язык, здесь есть небольшая кривая обучения. Он очень похож на Java, но также включает некоторые элементы синтаксиса Groovy и Scala, например, метод определяется ключевым словом def, переменная - var или val, в противном случае вы можете писать такой же код, как Java. При желании вы можете использовать лямбда-методы, методы расширения (как в C #), многострочные текстовые литералы и многие другие полезности. Xtend имеет отличный плагин Eclipse, намного лучше, чем Scala, но не полностью такой же, как ванильный Java. При оценке переменных в отладчике были некоторые особенности. С помощью плагина Xtend вы можете увидеть, в какой чистый Java-код переводится Xtend-код в режиме реального времени. Нет плагина для Idea. Хорошо интегрирован с Maven.

Альтернатива

Сам Xtend основан на Xtext, фреймворке для простого создания новых языков. Используя его и Xbase, вы можете относительно легко создать новый язык, который будет точно таким же как Java, за исключением того, что оператор '+' будет переводить на все, что вы хотите. Кривая обучения гораздо более крутая, тогда вам придется прочитать большую часть документации Xtext.

person Espinosa    schedule 08.09.2014

Другой вариант - смешать Java и Scala. С помощью Scala вы можете делать то, что говорите (у меня нет реального опыта работы со Scala, но это должно быть довольно легко), плюс смешивание этих двух элементов тривиально.

См., Например, Scala: перегрузка метода \ оператора

Затем, если вы напишете свою библиотеку перегруженных арифметических функций, вы сможете вызывать их из Java, просто импортировав пакет Scala, как вы бы это делали в Java.

person cornuz    schedule 08.09.2014
comment
Прошу прощения, если я запутал вас. Но на самом деле мои методы написаны на java, поэтому мне нужно переписать их на Scala и импортировать класс операции, если я хочу использовать перегрузку оператора. - person Alex Vong; 09.09.2014
comment
Может, я не понимаю. Вы были готовы переписать их на C ++, но не на Scala? - person cornuz; 09.09.2014
comment
Это еще одна путаница, лол. Я не переписываю на C ++. Я его отредактирую. - person Alex Vong; 09.09.2014
comment
Это звучит глупо. Но я понял, что могу использовать конвертер. - person Alex Vong; 09.09.2014
comment
Я попробовал ваше предложение и установил плагин Scala для NetBeans. Но оказывается, что класс Int в Scala имеет модификатор final и abstract, поэтому я не могу расширить класс Int и переопределить оператор +, -, *, определенный в этом классе. Похоже, разработчики установили препятствия, чтобы кто-то не испортил их код. Вы знаете, как это решить? - person Alex Vong; 09.09.2014