Строковые параметры Java

Я исхожу из фона .net и хочу знать принятый способ создания метода, который возвращает логическое значение и изменяет строку, которая была передана через параметр. Я понимаю, что строки неизменяемы в Java, поэтому приведенный ниже фрагмент всегда будет создавать пустую строку. Я вынужден возвращать только логическое значение. Исключения не могут быть выброшены. Если мне нужно обернуть класс String, скажем, в StringHolder, в каком пакете я могу это найти.

public static void DoStuff()
{
    String msg = "";
    if (GetMessage(msg))
    {
       System.out.println(msg);
    }
}

person tgeros    schedule 05.12.2008    source источник
comment
Что мне нравится в этом вопросе, так это то, что я вынужден возвращать только логическое значение. Исключение не может быть выброшено. Они также скажут вам, что все циклы for должны выполняться как циклы while? Зачем использовать Java, если вам не разрешено использовать Java. Удачи.   -  person jmucchiello    schedule 20.12.2008
comment
Не могли бы вы уточнить, что вам нужно? Вы пишете, что я вынужден возвращать логическое значение, но объявление вашего метода читает public static void DoStuff()   -  person Bevan    schedule 20.12.2008
comment
@joe_mucchuiello Это единственный разработчик, который отказался использовать исключения или любые современные языковые идиомы. @Bevan Это метод GetMessage, который должен был вернуть логическое значение. Не так много DoStuff. Извиняюсь за путаницу.   -  person tgeros    schedule 24.12.2008


Ответы (11)


Используйте java.lang.StringBuilder - в основном изменяемую строку. Однако было бы безопаснее и более «в стиле Java» возвращать измененную строку.

person Michael Borgwardt    schedule 05.12.2008

Я настоятельно рекомендую вам не использовать StringBuilder, держатель и т.п. Они хакеры. Вы хотите работать со строками, а не с конструкторами.

Самый очевидный подход — вернуть объект, содержащий данные, которые вы хотите вернуть. Решение Дэвида [bombe.livejournal.com] охватывает это, поэтому я не буду повторяться. Тем не менее, я бы предложил вместо того, чтобы пытаться сделать общий набор данных, сделать его конкретным. Сделайте это как объект, возможно, это может даже привести к реальному поведению. (И если вы действительно хотите отправиться в город, скройте конструктор и вместо этого дайте ему статический метод создания.)

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

(Более важный) код использования будет выглядеть примерно так (выглядит немного странно, потому что он не конкретный и не общий):

String userMessage = thing.doStuff(new StuffHandler<String>() {
    public String stuff(boolean success, String message) {
        return message+" was "+(success ? "succesful" : "unsuccesful");
    }
});

Реализация выглядит примерно так:

public interface StuffHandler<T> {
    T stuff(boolean success, String message);
}

[...]

    public <T> T doStuff(StuffHandler<T> handler) {
        handler.stuff(isSuccess(), getMessage());
    }

Третий подход состоит в том, чтобы просто разбить метод на две части. Это может или не может быть осуществимо.

person Tom Hawtin - tackline    schedule 05.12.2008
comment
Спасибо Тому за приложенные усилия. У меня сработал StringBuilder, хотя, как вы говорите, это хак. Мне нужно было самое простое и понятное решение на данный момент. - person tgeros; 08.12.2008

Во-первых, у меня, вероятно, не было бы этих требований. Я уверен, что их можно обойти. Если вы не хотите этого делать, я бы рекомендовал вернуть объект-контейнер для ваших двух результатов:

public class ResultContainer {
    private final boolean success;
    private final String result;
    public ResultContainer(boolean success, String result) {
        this.success = success;
        this.result = result;
    }
    public boolean isSuccess() { return success; }
    public String getResult() { return result; }
}

И в вашем основном коде:

ResultContainer resultContainer = GetMessage(message);
if (resultContainer.isSuccess()) {
    System.out.println(resultContainer.getResult());
}

GetMessage(), очевидно, создаст новый экземпляр ResultContainer и вернет его, заполненный возвращаемыми значениями.

(Использование Generics для ResultContainerоставлено читателю в качестве упражнения.)

person Bombe    schedule 05.12.2008

Более элегантный класс держателя можно повторно использовать для любого типа объекта, используя дженерики:

public class Holder<T> {
  T item;
  public Holder( T item) { set( item);}
  public T get( ) { return item;}
  public void set( T item) { this.item = item;}
}

DoStuff( ) тогда будет выглядеть так:

public static void DoStuff( ) {
  String msg = "";
  Holder<String> holder = new Holder<String>( msg);
  if ( getMessage( holder)) { System.out.println( holder.get( ));}
}

и GetMessage( ) пришлось бы звонить holder.set( a_string).

person J. A. Faucett    schedule 05.12.2008

Java — это объектно-ориентированный язык, основанный на классах, поэтому его идиомы имеют тенденцию создавать классы для инкапсуляции данных с поведением, которое их окружает.

У вас есть данное — сообщение — которое каким-то образом получено, а затем, если выполняется какое-то условие, с ним делается что-то еще. Превращение этого поведения в последовательность get, if и других операций во внешнем управляющем объекте часто является признаком того, что программист не понял ООП.

Я вынужден возвращать только логическое значение. Исключения не могут быть выброшены.

Могу ли я предложить вам использовать Fortran или C, а не Java? В процедурных языках часто используется идиома мутации и возврата флага, которая хорошо подходит для этой парадигмы (при отсутствии автоматического управления памятью вызывающий объект создает буфер, который заполняется, и передает его; это позволяет безопасно освобождать буфер, когда вызывающая сторона закончила с этим; Java не нужно этого делать, поэтому, если вы посмотрите, скажем, на Map.get(), она возвращает String или null в случае сбоя - нет необходимости управлять памятью в вызывающей стороне). По крайней мере, не утруждайте себя попытками найти принятый способ сделать это в идиоматической Java - с этими ограничениями этого не будет, и тот, кто навязывает их вам, сделал плохой выбор, что будет означать, что у вас либо есть хаки , или в конечном итоге с подробным кодом, пытающимся создать решение без взлома.

person Pete Kirkham    schedule 05.12.2008

Вы не можете использовать строку в качестве выходного параметра. Вместо этого можно было бы использовать класс StringBuilder или вернуть null в случае сбоя.

Обсуждение здесь

person JamesSugrue    schedule 05.12.2008

Строки неизменяемы, поэтому да, вам нужно будет обернуть строку в StringHolder. Вы можете написать свой собственный так же просто, как

  class StringHolder
  {
     String msg;
  }

  StringHolder sMsg = new StringHolder();
  sMsg.msg = "";
  if (GetMessage(sMsg))
  {
     System.out.println(sMsg.msg);
  }
person Paul Tomblin    schedule 05.12.2008

Тривиальным StringHolder будет String[1].


bool GetMessage(String[] output)
{
     if(output.length < 1)
          throw new Exception("Output must be a String[1]");
     output[0] = "You win!";
}

public static void DoStuff()
{
      String[] msg = new String[1];
      if(GetMessage(msg))
      {
          System.out.println(msg[0]);
      }
}

Однако StringBuilder, вероятно, является каноническим способом сделать это.

person Stobor    schedule 05.12.2008

Какое-то странное требование.

Почему бы не сделать это правильно (или, по крайней мере, способом Java)? Это похоже на попытку получить два результата от функции. Подобно вычитанию ( 2 , 2 ) возвращает 0 и «Доброе утро, сэр».

В любом случае, вы можете попробовать эти два варианта.

1-й. StringBuilder Не лучший вариант для использования, так как вы не "строите" строку.

public static void doStuff(){
    String msg = "";
    StringBuilder sb = new StringBuilder();
    if ( getMessage( sb ) ) {
        System.out.println( sb );
    }
}

public static boolean getMessage( StringBuilder sb ) {
    if ( "".equals( sb.toString() )) {
        sb.delete( 0, sb.length() );
        sb.append("It was empty");
        return true;
    } else {
        return false;
    }
}

2-й StringHolder (любой держатель, если на то пошло) Не ​​слишком стиль Java, но делает работу. Это будет тот, который используется большинством разработчиков Java, которых я знаю.

public static void doStuff(){
    String msg = "";
    String [] holder = { msg };
    if ( getMessage( holder ) ){
        System.out.println( holder[0]  );
    }
}
public static boolean getMessage( String [] holder ) {
    if ( "".equals(  holder[0] )) {
        holder[0] = "It was empty";
        return true;
    } else {
        return false;
    }
}

3-й. Вариант. не то, что вы спросили, а то, что я бы сделал. К сожалению, нарушает условие "возврат логического значения".

public void doStuff() { 
    String msg = "";
    String result = getMessage( msg );
    if ( result != msg ) {
        System.out.println( result );
    }
}
public static String getMessage( String msg ) {
    if ( "".equals(msg){
        return "It was empty";
    }
    return msg
}

Выбери один.

Примечание

Хотя это нравится не всем (Джон Скит сказал бы: «Это не общепринято»), пожалуйста, взгляните на стиль программирования Java, который я использую (методы, начинающиеся с нижнего регистра и фигурные скобки в одной строке). Иногда важно уважать платформу, на которой вы кодируете. По крайней мере, это то, что я делаю, когда кодирую на С# (очень редко, кстати).

person OscarRyz    schedule 05.12.2008
comment
если ( результат != сообщение )? Тск, тск! - person Alan Moore; 05.12.2008
comment
Я никогда не утверждал, что соглашения об именовании не являются общепринятыми. Только стиль крепления. Это потому, что не имеет значения, как Sun скрепляет свой код — несоответствие между моим кодом и их кодом не проявляется в моем коде. Именование имеет значение, потому что я использую классы Sun в своем коде. - person Jon Skeet; 05.12.2008

public boolean doStuff(String msg) { boolean boolTest = false; msg += "Appending something to msg"; int msgLength = msg.length(); if ( msgLength > 80 ) { boolTest = true; return boolTest; } return boolTest; }

Это то, что вы ищете? Я предполагаю, что логический тест - это что-то вроде проверки того, является ли измененное сообщение слишком длинным для отображения (длиной более 80) или что-то подобное, и что вам не нужно вызывать другой метод для изменения строки сообщения внутри doStuff ().

Хотя здесь может быть совершенно не по адресу. :-)

person Community    schedule 20.12.2008

сначала вы пишете программы и делаете их из такого кода:

Process p = Runtime.exec("java GetMessage.class " + String);

Совет для вас: Runtime.exec следует использовать везде. Тогда вы можете сделать много программ.

Затем вы ждете, чтобы получить код состояния, подобный этому:

if (p.returnCode() = 1) 
  Out.printWord("1 made back"):
else 
  {
  Out.printWord("B Made back");
  }

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

person Community    schedule 20.12.2008