Javaでfinalキーワードを使用すると、パフォーマンスが向上しますか?


347

Javaでは、finalキーワードを使用できる場所がたくさんありますが、その使用は一般的ではありません。

例えば:

String str = "abc";
System.out.println(str);

上記の場合、strは可能ですfinalが、通常は省略されます。

メソッドがオーバーライドされない場合は、finalキーワードを使用できます。同様に継承されないクラスの場合。

これらのケースのいずれかまたはすべてでfinalキーワードを使用すると、本当にパフォーマンスが向上しますか?もしそうなら、どのように?説明してください。finalパフォーマンスを適切に使用することが重要である場合、Javaプログラマーはキーワードを最大限に活用するためにどのような習慣を身につけるべきですか?


私はそう思っていません。メソッドのディスパッチ(呼び出しサイトのキャッシュなど)は、静的型言語ではなく動的言語の問題です
Jahan

レビュー目的で使用する私のPMDツール(Eclipseへのプラグイン)を実行する場合、上記のように変数を変更することをお勧めします。しかし、私はその概念を理解していませんでした。本当にパフォーマンスはそんなに打撃を受けますか?
Abhishek Jain

5
これは典型的な試験問題だと思いました。final パフォーマンスに影響を与えることを覚えてます。IIRCfinalクラスはサブクラス化できないため、JREによって何らかの方法で最適化できます。
Kawu

私は実際にこれをテストしてもらいました。すべてのJVMでローカル変数のfinalの使用をテストしたところ、パフォーマンス向上しました(わずかですが、それでもユーティリティメソッドの要因になる可能性があります)。ソースコードは以下の私の答えにあります。
rustyx 2014年

1
「時期尚早な最適化はすべての悪の根源です」。コンパイラーに処理を任せてください。読みやすく、適切なコメント付きコードを記述します。それは常に最良の選択です!
カイザー2017

回答:


285

通常はありません。仮想メソッドの場合、HotSpotはメソッドが実際にオーバーライドされているかどうかを追跡し、メソッドがオーバーライドされていないという仮定に基づいてインライン化などの最適化を実行できます。これらの最適化を元に戻す(または部分的に元に戻す)ことができます。

(もちろん、これはHotSpotを使用していることを前提としていますが、これは明らかに最も一般的なJVMなので、...)

私の考えfinalでは、パフォーマンス上の理由ではなく、明確な設計と読みやすさに基づいて使用する必要があります。パフォーマンス上の理由で何かを変更したい場合は、最も明確なコードを形から曲げる前に適切な測定を実行する必要があります。これにより、達成された追加のパフォーマンスが読みやすさ/デザインの悪さに見合うかどうかを判断できます。(私の経験では、それはほとんど価値がありません; YMMV。)

編集:最終的なフィールドが言及されたので、明確なデザインの観点から、それらはしばしばとにかく良いアイデアであることを育てることは価値があります。また、スレッド間の可視性に関して保証された動作も変更します。コンストラクターが完了した後、最終フィールドは他のスレッドですぐに表示されることが保証されています。これはおそらくfinal私の経験では最も一般的な使用法ですが、ジョシュ・ブロッホの「継承の設計または禁止」の経験則の支持者として、私はおそらくfinalクラスでより頻繁に使用する必要があります...


1
@Abhishek:特に何についてですか?最も重要な点は最後の点です-ほとんどの場合、これについて心配する必要はありません。
Jon Skeet、2010年

9
@Abishek:finalコードを理解しやすくし、バグを見つけるのに役立つため、一般的に推奨されます(プログラマーが明示的に意図するため)。PMD finalは、パフォーマンス上の理由ではなく、これらのスタイルの問題のために使用することをお勧めします。
sleske 2010年

3
@Abhishek:その多くはJVM固有である可能性が高く、コンテキストの非常に微妙な側面に依存している可能性があります。たとえば、HotSpot サーバーの JVMでは、1つのクラスでオーバーライドされた場合でも仮想メソッドのインライン化が可能であり、必要に応じてクイックタイプチェックを行うことができます。しかし、詳細を特定するのは難しく、リリースごとに変わる可能性があります。
Jon Skeet

5
ここでは、Effective Java、2nd Edition、Item 15、Minimize mutability:を引用しますImmutable classes are easier to design, implement, and use than mutable classes. They are less prone to error and are more secure.。さらに、An immutable object can be in exactly one state, the state in which it was created.VS Mutable objects, on the other hand, can have arbitrarily complex state spaces.。私の個人的な経験から、キーワードを使用finalすると、コードを「最適化」するのではなく、不変性に傾くという開発者の意図が強調されます。この章を読むことをお勧めします。
Louis F.

2
他の回答は、final変数にキーワードを使用すると、バイトコードの量が減り、パフォーマンスに影響を与える可能性があることを示しています。
Julien Kronegg、

86

短い答え:心配しないでください!

長い答え:

最終的なローカル変数について話すとき、キーワードを使用するfinalと、コンパイラーがコードを静的に最適化するのに役立ち、最終的にはより高速なコードが得られる可能性があることに注意してください。たとえば、次の例の最後の文字a + b列は、静的に(コンパイル時に)連結されます。

public class FinalTest {

    public static final int N_ITERATIONS = 1000000;

    public static String testFinal() {
        final String a = "a";
        final String b = "b";
        return a + b;
    }

    public static String testNonFinal() {
        String a = "a";
        String b = "b";
        return a + b;
    }

    public static void main(String[] args) {
        long tStart, tElapsed;

        tStart = System.currentTimeMillis();
        for (int i = 0; i < N_ITERATIONS; i++)
            testFinal();
        tElapsed = System.currentTimeMillis() - tStart;
        System.out.println("Method with finals took " + tElapsed + " ms");

        tStart = System.currentTimeMillis();
        for (int i = 0; i < N_ITERATIONS; i++)
            testNonFinal();
        tElapsed = System.currentTimeMillis() - tStart;
        System.out.println("Method without finals took " + tElapsed + " ms");

    }

}

結果?

Method with finals took 5 ms
Method without finals took 273 ms

Java Hotspot VM 1.7.0_45-b18でテスト済み。

では、実際のパフォーマンスの向上はどの程度ですか?あえて言わない。ほとんどの場合、限界的です(文字列の連結が完全に回避されるため、この模擬テストでは約270ナノ秒-まれなケース)。ただし、高度に最適化されたユーティリティコードで、それ要因になる可能性があります。いずれの場合でも、元の質問に対する答えは「はい」です。パフォーマンスは向上する可能性がありますが、せいぜい最高です。

コンパイル時の利点はさておき、キーワードの使用がfinalパフォーマンスに測定可能な影響を与えるという証拠は見つかりませんでした。


2
両方のケースを100回テストするために、コードを少し書き直しました。最終的に、ファイナルの平均時間は0ミリ秒で、ファイナルではないものは9ミリ秒でした。反復カウントを10Mに増やすと、平均が0ミリ秒と75ミリ秒に設定されます。非ファイナルのベストランは0ミリ秒でした。たぶんそれは、VMの検出結果がただ捨てられているだけなのでしょうか?わかりませんが、とにかく、finalを使用すると大きな違いがあります。
CasperFærgemand2014

5
欠陥のあるテスト。以前のテストはJVMをウォームアップし、後のテストの呼び出しに役立ちます。テストを並べ替えて、何が起こるかを確認します。独自のJVMインスタンスで各テストを実行する必要があります。
Steve Kuo 14年

16
テストに欠陥はなく、ウォームアップが考慮されました。2番目のテストは低速であり、高速ではありません。ウォームアップがなければ、2番目のテストはEVEN SLOWERになります。
rustyx 2014

6
testFinal()では、文字列プールから常に同じオブジェクトが返されました。これは、最終的な文字列のリサスと文字列リテラルの連結がコンパイル時に評価されるためです。testNonFinal()は、新しいオブジェクトを返すたびに、速度の違いを説明します。
2014年

4
シナリオが非現実的だと思うのはなぜですか?String連結は、を追加するよりもはるかにコストのかかる操作ですIntegers。静的に(可能な場合)行う方が効率的です。それがテストで示されていることです。
rustyx 2014

62

はい、できます。次に、finalがパフォーマンスを向上できる例を示します。

条件付きコンパイルは、特定の条件に基づいてコード行をクラスファイルにコンパイルしない手法です。これは、製品ビルドで大量のデバッグコードを削除するために使用できます。

以下を検討してください。

public class ConditionalCompile {

  private final static boolean doSomething= false;

    if (doSomething) {
       // do first part. 
    }

    if (doSomething) {
     // do second part. 
    }

    if (doSomething) {     
      // do third part. 
    }

    if (doSomething) {
    // do finalization part. 
    }
}

doSomething属性をfinal属性に変換することにより、doSomethingを検出した場合は常に、コンパイル時の置換規則に従ってfalseに置き換える必要があることをコンパイラーに伝えました。コンパイラの最初のパスは、コードを次のように変更します。

public class ConditionalCompile {

  private final static boolean doSomething= false;

    if (false){
       // do first part. 
    }

    if (false){
     // do second part. 
    }

    if (false){
      // do third part. 
    }

    if (false){
    // do finalization part. 

    }
}

これが完了すると、コンパイラはそれを再度調べ、コード内に到達できないステートメントがあることを確認します。最高品質のコンパイラを使用しているので、到達できないバイトコードのすべてが好きではありません。だからそれらを削除し、あなたはこれで終わります:

public class ConditionalCompile {


  private final static boolean doSomething= false;

  public static void someMethodBetter( ) {

    // do first part. 

    // do second part. 

    // do third part. 

    // do finalization part. 

  }
}

したがって、過剰なコードや不要な条件チェックを削減します。

編集:例として、次のコードを見てみましょう:

public class Test {
    public static final void main(String[] args) {
        boolean x = false;
        if (x) {
            System.out.println("x");
        }
        final boolean y = false;
        if (y) {
            System.out.println("y");
        }
        if (false) {
            System.out.println("z");
        }
    }
}

このコードをJava 8でコンパイルしjavap -c Test.classて逆コンパイルすると、次のようになります。

public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public static final void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_1
       2: iload_1
       3: ifeq          14
       6: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
       9: ldc           #22                 // String x
      11: invokevirtual #24                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      14: iconst_0
      15: istore_2
      16: return
}

コンパイルされたコードには、最終でない変数のみが含まれることに注意してくださいx。これにより、少なくともこの単純なケースでは、最終的な変数がパフォーマンスに影響を与えることが証明されます。


1
@ŁukaszLech私はこれをOreillyの本:Hardcore Javaから、最後のキーワードに関する章で学びました。
mel3kings 2013年

15
これはコンパイル時の最適化について話します。つまり、開発者はコンパイル時の最終ブール変数のVALUEを知っています。つまり、ブロックが最初にある場合、IF-CONDITIONSが不要であり、何か意味は?私の意見では、これがパフォーマンスを向上させたとしても、これは最初は間違ったコードであり、コンパイラに責任を渡すのではなく、開発者自身が最適化することができ、質問は主にfinalが使用される通常のコードのパフォーマンス改善について尋ねることを意図していますプログラム的に意味があります。
Bhavesh Agarwal 2013

7
これのポイントは、mel3kingsが述べたようにデバッグステートメントを追加することです。プロダクションビルドの前に変数を反転(またはビルドスクリプトで構成)し、ディストリビューションの作成時にすべてのコードを自動的に削除できます。
Adam

37

IBMによると、クラスやメソッドには対応していません。

http://www.ibm.com/developerworks/java/library/j-jtp04223.html


1
...とIBMによると、それはフィールドにありませんibm.com/developerworks/java/library/j-jtp1029/...は -ともベストプラクティスとして促進されます。
Philzen

2
記事「04223」は2003年のものです。現在17年近く経過しています。それは... Java 1.4でしたか?
dmatej

16

少なくともいくつかの小さな違いがあることを証明するために逆コンパイルされた実際のコードを実際に投稿した人はいないことに驚きます。

参考のために、これはjavacバージョン89およびに対してテストされてい10ます。

このメソッドを想定します。

public static int test() {
    /* final */ Object left = new Object();
    Object right = new Object();

    return left.hashCode() + right.hashCode();
}

このコードをそのままコンパイルすると、存在する場合とまったく同じバイトコードが生成finalされます(final Object left = new Object();)。

しかし、これは:

public static int test() {
    /* final */ int left = 11;
    int right = 12;
    return left + right;
}

生成する:

   0: bipush        11
   2: istore_0
   3: bipush        12
   5: istore_1
   6: iload_0
   7: iload_1
   8: iadd
   9: ireturn

立ち会うfinalと、次のような結果になります。

   0: bipush        12
   2: istore_1
   3: bipush        11
   5: iload_1
   6: iadd
   7: ireturn

コードはほとんど自明です。コンパイル時定数がある場合、コードはオペランドスタックに直接ロードされます(前の例のようにローカル変数配列に格納されませんbipush 12; istore_0; iload_0)-これは一種の意味があります誰もそれを変えることができないからです。

一方、2番目のケースでコンパイラが生成しない理由はistore_0 ... iload_0私を超えているため、そのスロット0がどのように使用されているかとは異なります(変数の配列をこのように縮小できますが、内部の詳細が不足している可能性があります。確かに言う)

このような最適化を見て驚いたのは、どれだけ小さいのかを考えてjavacいたからです。いつも使うべきfinalか?私はJMHテストを作成するつもりはありませんが(最初にしたかったのですが)、diffがns(可能な場合はまったくキャプチャーできる)のオーダーにあると確信しています。これが問題になる可能性がある唯一の場所は、サイズが原因でメソッドをインライン化できなかった場合です(宣言finalすると、サイズが数バイト縮小されます)。

final対処する必要のあるがさらに2つあります。1つは、メソッドがfinalJIT観点から)である場合、そのようなメソッドは単形であり、これらはによって最も愛されているメソッドですJVM

次に、finalインスタンス変数があります(すべてのコンストラクターで設定する必要があります)。これらは、ここ少し触れたように正しく公開された参照を保証し、またによって正確に指定されているため、重要JLSです。


デバッグオプション(javac -g FinalTest.java)でJava 8(JDK 1.8.0_162)を使用javap -c FinalTest.classしてコードをコンパイルし、使用してコードを逆コンパイルしましたが、同じ結果が得られませんでした(final int left=12、を得ましたbipush 11; istore_0; bipush 12; istore_1; bipush 11; iload_1; iadd; ireturn)。つまり、生成されたバイトコードは多くの要因に依存しておりfinal、パフォーマンスに影響があるかどうかを判断するのは困難です。ただし、バイトコードが異なるため、パフォーマンスに多少の違いが生じる可能性があります。
ジュリアンクロネッグ


13

あなたは本当に2つの(少なくとも)異なるケースについて尋ねています:

  1. final ローカル変数
  2. final メソッド/クラス用

Jon Skeetはすでに2)と回答しています。1)について:

違いはないと思います。ローカル変数の場合、コンパイラーは変数が最終であるかどうかを推定できます(単に、変数が複数回割り当てられているかどうかを確認することにより)。したがって、コンパイラーが一度だけ割り当てられる変数を最適化したい場合は、変数が実際に宣言されているかどうかに関係なく最適化できますfinal

final プロテクト/パブリッククラスフィールドに違いが生じる可能性があります。フィールドが複数回設定されているかどうかは、別のクラス(ロードされていない場合もある)から発生する可能性があるため、コンパイラが見つけるのは非常に困難です。しかし、その場合でも、JVMはJonが説明する手法を使用できます(楽観的に最適化し、フィールドを変更するクラスがロードされている場合は元に戻します)。

要約すると、それがパフォーマンスに役立つ理由は何も見当たりません。したがって、この種のミクロ最適化は役に立たないでしょう。あなたはそれを確かめるためにそれをベンチマークすることを試みることができます、しかし私はそれが違いを生むことを疑います。

編集:

実際、TimoWestkämperの回答によると、場合によってはクラスフィールドのパフォーマンスを向上させるfinal ことができます。私は修正された立場です。


コンパイラがローカル変数が割り当てられた回数を正しくチェックできないと思います:多数の割り当てがあるif-then-else構造体はどうですか?
gyorgyabraham 2013年

1
@gyabraham:ローカル変数をとして宣言した場合、コンパイラーはこれらのケースをすでにチェックしてfinal、2回割り当てないようにします。私が見る限り、同じチェックロジックを使用して、変数がそうであるかどうかをチェックできます(おそらくそうです)final
sleske 2013年

ローカル変数の最終性はバイトコードで表現されないため、JVMはそれが最終的なものであることさえ知りません
Steve Kuo

1
@SteveKuo:バイトコードで表現されていない場合でも、javac最適化に役立つ場合があります。しかし、これは単なる推測です。
sleske 2014年

1
コンパイラーは、ローカル変数が正確に1回割り当てられているかどうかを検出できますが、実際には(エラーチェックを超えて)割り当てられていません。一方、final変数がプリミティブ型または型でStringあり、質問の例のようにコンパイル時定数がすぐに割り当てられる場合、変数は仕様ごとのコンパイル時定数であるため、コンパイラーインライン化する必要があります。しかし、ほとんどのユースケースでは、コードは異なって見えるかもしれませんが、定数がインライン化されていても、ローカル変数からパフォーマンス的に読み取られていても、違いはありません。
Holger

6

注:Javaエキスパートではありません

私のJavaを正しく覚えている場合、finalキーワードを使用してパフォーマンスを向上させる方法はほとんどありません。私はそれが「良いコード」-デザインと読みやすさのために存在することを常に知っていました。


1

私はエキスパートfinalではありませんが、上書きされない場合は、クラスまたはメソッドにキーワードを追加して、変数をそのままにしておく必要があります。そのようなことを最適化する方法がある場合、コンパイラーがそれを行います。


1

実際、一部のOpenGL関連のコードをテストしているときに、プライベートフィールドでfinal修飾子を使用するとパフォーマンスが低下することわかりました。これが私がテストしたクラスの始まりです:

public class ShaderInput {

    private /* final */ float[] input;
    private /* final */ int[] strides;


    public ShaderInput()
    {
        this.input = new float[10];
        this.strides = new int[] { 0, 4, 8 };
    }


    public ShaderInput x(int stride, float val)
    {
        input[strides[stride] + 0] = val;
        return this;
    }

    // more stuff ...

そして、これは私がさまざまな選択肢のパフォーマンスをテストするために使用したメソッドであり、その中でShaderInputクラスは次のとおりです。

public static void test4()
{
    int arraySize = 10;
    float[] fb = new float[arraySize];
    for (int i = 0; i < arraySize; i++) {
        fb[i] = random.nextFloat();
    }
    int times = 1000000000;
    for (int i = 0; i < 10; ++i) {
        floatVectorTest(times, fb);
        arrayCopyTest(times, fb);
        shaderInputTest(times, fb);
        directFloatArrayTest(times, fb);
        System.out.println();
        System.gc();
    }
}

3回目の反復の後、VMがウォームアップしたため、最後のキーワードなしで次の数字が一貫して得られました。

Simple array copy took   : 02.64
System.arrayCopy took    : 03.20
ShaderInput took         : 00.77
Unsafe float array took  : 05.47

finalキーワード:

Simple array copy took   : 02.66
System.arrayCopy took    : 03.20
ShaderInput took         : 02.59
Unsafe float array took  : 06.24

ShaderInputテストの図に注意してください。

フィールドをパブリックにするかプライベートにするかは関係ありませんでした。

ちなみに、さらにいくつかの不可解な点があります。ShaderInputクラスは、finalキーワードを使用しても、他のすべてのバリアントよりも優れています。これは注目に値するb / cです。基本的にはfloat配列をラップするクラスですが、他のテストは配列を直接操作します。これを理解する必要があります。ShaderInputの流暢なインターフェイスと関係がある可能性があります。

また、System.arrayCopyは、forループで単純に1つの配列から別の配列に要素をコピーするよりも、小さな配列の方が明らかに明らかに低速です。そして、sun.misc.Unsafe(および直接java.nio.FloatBuffer、ここには示されていません)を使用すると、非常に小さなパフォーマンスを発揮します。


1
パラメータをfinalにするのを忘れました。<pre> <code> public ShaderInput x(final int stride、final float val){input [strides [stride] + 0] = val; これを返す; } </ code> </ pre>私の経験では、変数またはフィールドのfinalを実行すると、実際にパフォーマンスが向上する場合があります。
Anticro、2016年

1
ああ、また他のものもfinalにします:<pre> <code> final int arraySize = 10; final float [] fb = new float [arraySize]; for(int i = 0; i <arraySize; i ++){fb [i] = random.nextFloat(); } final int times = 1000000000; for(int i = 0; i <10; ++ i){floatVectorTest(times、fb); arrayCopyTest(回、fb); shaderInputTest(回、fb); directFloatArrayTest(times、fb); System.out.println(); System.gc(); } </ code> </ pre>
Anticro、2016年

1

最終(少なくともメンバー変数とパラメーターの場合)は、人間の場合よりも機械の場合の方が多くなります。

可能な限り変数をfinalにすることをお勧めします。私はJavaがデフォルトで「変数」をfinalにして、変更を許可する「Mutable」キーワードがあったらいいのにと思います。不変クラスを使用すると、スレッド化されたコードが大幅に改善され、各メンバーの前に「最終」があるクラスを一瞥するだけで、そのクラスが不変であることがすぐにわかります。

別のケース-@ NonNull / @ Nullableアノテーションを使用するように多くのコードを変換してきました(メソッドパラメータをnullにすることはできません。そうすると、IDEは、タグが付けられていない変数を渡すすべての場所に警告を表示します。 NonNull-すべてがばかばかしいほど広がっています)。メンバー変数またはパラメーターがfinalとタグ付けされている場合、他の場所に再割り当てされていないことがわかっているため、メンバー変数またはパラメーターをnullにできないことを証明する方がはるかに簡単です。

私の提案は、デフォルトでメンバーとパラメーターにfinalを適用する習慣を身に付けることです。これはほんの数文字ですが、コーディングスタイルの改善に向けて何もしていません。

メソッドまたはクラスのfinalは、非常に有効な形式の再利用を許可せず、実際に読者に多くのことを伝えないため、別の概念です。最良の使用法は、おそらくStringと他の組み込み型をfinalにした方法であるため、どこでも一貫した動作に依存することができます-これにより、多くのバグが防止されました(文字列を拡張するのが大好きな場合もあります...可能性)


0

他の場所で述べたように、ローカル変数の「最終」、およびメンバー変数のわずかな程度は、スタイルの問題です。

「最終」は、変数を変更しないことを意図するステートメントです(つまり、変数は変化しません!)。コンパイラーは、ユーザーが独自の制約に違反しているかどうかを文句を言うことで支援できます。

識別子(申し訳ありませんが、変化しないものを「変数」と呼ぶことはできません)がデフォルトで最終的なものであり、それらが変数であると明示するように要求した場合、Javaの方がより良い言語であるという意見を共有します。しかし、そうは言っても、初期化されて割り当てられていないローカル変数に対しては通常「final」を使用しません。うるさすぎるようです。

(私はメンバー変数にfinalを使用しています)


-3

finalで宣言されたメンバーは、プログラムで使用できます。final以外のメンバーとは異なり、これらのメンバーがプログラムで使用されていない場合でも、ガベージコレクターによって処理されないため、メモリ管理が不適切なためにパフォーマンスの問題が発生する可能性があります。


2
これはどんなナンセンスですか?これが事実だと思う理由はありますか?
J. Doe、

-4

final キーワードはJavaで5つの方法で使用できます。

  1. クラスは最終です
  2. 参照変数は最終です
  3. ローカル変数は最終です
  4. メソッドは最終です

クラスは最終的なものです。クラスは最終的なものであり、拡張できないこと、または継承は継承が不可能であることを意味します。

同様に-オブジェクトは最終です。オブジェクトの内部状態を変更しないことがあるので、そのような場合、オブジェクトが最終オブジェクトであることを指定できます。オブジェクト最終は、変数でも最終でもないことを意味します。

参照変数を確定すると、他のオブジェクトに再割り当てできなくなります。ただし、フィールドがfinalでない限り、オブジェクトの内容を変更できます


2
「オブジェクトは最終的」とは、「オブジェクトは不変」を意味します。
gyorgyabraham 2013年

6
あなたは正しいですが、あなたは質問に答えていません。OPは何をfinal意味するか尋ねませんでしたが、使用finalがパフォーマンスに影響するかどうかを尋ねました。
Honza Zidek 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.