Разопаковане на Guava по избор в един израз

Като разработчик на Scala, който също работи в GWT, приветствам добавянето на Optional към Guava.

Един от нашите най-чести случаи на използване на Optional е при връщане на незадължителни стойности от методи (както е предложено от отговора на Какъв е смисълът на незадължителния клас на Guava.

В scala често пиша код като този:

def someExpensiveOperation(params: Type): Option[ResultType] = ...
someExpensiveOperation(params).foreach({ val =>
  doSomethingWithVal (val)
})

Опцията на Guava изглежда не позволява нищо по-елегантно от нещо подобно:

Optional<MyType> optionalResponse = someExpensiveOperation(params);
if (optionalResponse.isPresent()) {
    doSomethingWithVal(optionalResponse.get())
}

Локалната променлива е излишна и изисква повтаряне на модел, който може да бъде абстрахиран (if (optional.isPresent()) { doSomethingWith(optional.get()) }).

Другата опция е да извикате метода, който връща Optional два пъти:

if (someExpensiveOperation(params).isPresent()) {
    doSomethingWithVal(someExpensiveOperation(params).get())
}

Но това очевидно е нежелателно, тъй като извиква скъпа операция многократно ненужно.

Любопитен съм как други хора са се справили с този много често срещан случай (може би като са написали статичен полезен метод като <T>useIfPresent(Optional<T> val, Closure<? super T> closure)?) или дали някой е намерил по-елегантни решения.

Също така, ако някой знае защо метод като Optional.foreach(Closure<? super T> closure) (но се надяваме, че е по-добре наречен) е пропуснат, бих бил любопитен да чуя обосновката.


person Yona Appletree    schedule 08.12.2012    source източник


Отговори (1)


Не е там, защото смятаме, че неудобството на анонимния клас при писането на Closure е по-неудобно и по-малко четливо - поне в Java, не непременно в Scala - отколкото локалната променлива и оператора if, които вече сте написали.

Това каза, друга алтернатива е

for (Foo x : someExpensiveOperation().asSet()) {
  // do stuff with x
}

Обърнете внимание, че asSet е необходимо тук -- Optional съвсем умишлено не прилага Iterable.

person Louis Wasserman    schedule 08.12.2012
comment
Малко OT, но се чудя защо Optional.asSet() връща Set вместо ImmutableSet, след като е документирано да връща неизменно. Дали защото Optional се доставя в c.g.c.base, а не в c.g.c.collect? - person Xaerxess; 08.12.2012
comment
Това е точно така. (Системата за изграждане на Google повече или по-малко забранява цикличните зависимости на пакета.) - person Louis Wasserman; 08.12.2012
comment

както в заглавието, на някои устройства изображенията трептят, докато се извиква notifydatasetchanged.

Ето моя метод getView от моя подклас на BaseAdapter:

@Override
public View getView(int position, View convertView, ViewGroup arg2) {
    String infService = Context.LAYOUT_INFLATER_SERVICE;
    LayoutInflater li = (LayoutInflater)context.getSystemService(infService);
    View v = arg1;
    final ViewHolder holder;

    if(v == null)
    {
        v = li.inflate(R.layout.row_history_settings, arg2, false);
        holder = new ViewHolder();

        holder.flag = (ImageView) v.findViewById(R.id.row_history_settings_image_flag);
        holder.currency = (TextView) v.findViewById(R.id.row_history_settings_text_currency);
        holder.tb = (ToggleButton) v.findViewById(R.id.row_history_settings_tb);
        v.setTag(holder);
    }
    else
    {
        holder = (ViewHolder) v.getTag();
    }

    Account account = accounts.get(arg0);

    int resID = enabled == true ? Utils.getFlagResIdForCurrency(account.currency()) : Utils.getFlagInactiveResIdForCurrency(account.currency());

    if(resID != holder.resId)
    {   
        holder.resId = resID;
        holder.flag.setTag(resID);
        new AsyncImageLoader(holder.flag, context).execute();
    }

    holder.currency.setText(account.currency());
    if(currency!=null)
    {
        holder.tb.setChecked(currency.equals(account.currency()));
        holder.tb.setEnabled(true);
    }
    else
    {
        holder.tb.setChecked(false);
        holder.tb.setEnabled(false);
    }

    holder.tb.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            currency = holder.currency.getText().toString();
            notifyDataSetChanged();
        }
    });

    Utils.enableDisableView(v, enabled);

    return v;
}

Изображението на holder.flag трепти за различен кратък период от време всеки път, когато щракна върху бутона за превключване. Това изглежда се случва само на някои устройства като Sony Xperia U или HTC Desire Z.

Ето моето оформление на реда:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="@dimen/row_list_standard_height"
    android:background="@drawable/list_item_background"
    android:gravity="center_vertical"
    android:orientation="horizontal" >

    <ImageView
        android:id="@+id/row_history_settings_image_flag"
        android:layout_width="@dimen/row_list_flag_width"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="10dp"
        android:adjustViewBounds="true"
        android:contentDescription="@string/none"
        android:src="@drawable/flag_pln" />

    <com.aliorbank.components.customfont.CustomFontTextView
        android:id="@+id/row_history_settings_text_currency"
        style="@style/textViewUniversalRobotoLightBlack"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_gravity="left|center_vertical"
        android:layout_marginLeft="20dp"
        android:layout_toRightOf="@id/row_history_settings_image_flag"
        android:text="@string/universal_currency_pln"
        android:textSize="@dimen/font_size_big" />

    <ToggleButton
        android:id="@+id/row_history_settings_tb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="10dp"
        android:background="@drawable/btn_radio_standard"
        android:checked="true"
        android:text="@string/none"
        android:textOff="@string/none"
        android:textOn="@string/none" />
</RelativeLayout>

и моя клас AsyncIMageLoader:

public class AsyncImageLoader extends AsyncTask<Object, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private Context context;
private int resId;

public AsyncImageLoader(ImageView imv, Context context)
{
    imageViewReference = new WeakReference<ImageView>(imv);
    this.context = context;
    this.resId = (Integer)imv.getTag();
}

@Override
protected Bitmap doInBackground(Object... arg0) {
    return BitmapFactory.decodeResource(context.getResources(), resId);
}

@Override
protected void onPostExecute(Bitmap result) {

    if (imageViewReference != null && result != null) {
        final ImageView imageView = imageViewReference.get();
        if (imageView != null) {
            imageView.setImageBitmap(result);
        }
    }
}}

Струва ми се, че convertView не съответства на позицията в метода getView. Има ли някакъв начин да получите convertView, който съответства на позицията на реда на listview? Или може би има друго решение?

- person Yona Appletree; 11.12.2012
comment
Посетете отново? Може би. Google все още е в процес на преминаване към JDK7, да не говорим за 8; имаме много потребители, които ще бъдат на JDK 5 в обозримо бъдеще. Ще видим какво ще стане. - person Louis Wasserman; 11.12.2012
comment
JDK 5? Това е много лошо. Лозунгът на Guava е Guava: Google Core Libraries for Java 1.6+ :) - person Piotr Findeisen; 17.12.2012
comment
Понастоящем поддържаме отделен бекпорт за потребителите на JDK5. (Но например много от нашите потребители са приложения за Android, които се нуждаят от съвместимост с Froyo, която е сравнима с JDK5.) - person Louis Wasserman; 17.12.2012